Added std::string read/write by belal. Extremely volatile.

develop
Petr Mrázek 2010-02-16 00:04:15 +01:00
parent 568fcd6105
commit 56969fb977
18 changed files with 1240 additions and 589 deletions

@ -2,7 +2,6 @@
SET(PROJECT_HDRS
DFCommonInternal.h
DFDataModel.h
DFHackAPI.h
DFMemInfo.h
DFMemInfoManager.h
@ -24,7 +23,6 @@ tinyxml/tinyxml.h
)
SET(PROJECT_SRCS
DFDataModel.cpp
DFMemInfo.cpp
DFMemInfoManager.cpp
DFHackAPI.cpp
@ -47,6 +45,7 @@ stdint_win.h
SET(PROJECT_SRCS_LINUX
DFProcess-linux.cpp
DFProcess-linux-SHM.cpp
DFProcess-linux-wine.cpp
DFWindow-linux.cpp
DFProcessEnumerator-linux.cpp
)

@ -92,7 +92,7 @@ namespace DFHack
#endif
#include "DFTypes.h"
#include "DFDataModel.h"
//#include "DFDataModel.h"
#include "DFProcess.h"
#include "DFWindow.h"
#include "DFProcessEnumerator.h"

@ -1,164 +0,0 @@
/*
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;
DfVector DMWindows40d::readVector (uint32_t offset, uint32_t item_size)
{
/*
MSVC++ vector is four pointers long
ptr allocator
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
we also don't care about the allocator thing in front
*/
uint32_t start = g_pProcess->readDWord(offset+4);
uint32_t end = g_pProcess->readDWord(offset+8);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
size_t DMWindows40d::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
size_t length = g_pProcess->readDWord(offset + 20);
size_t capacity = g_pProcess->readDWord(offset + 24);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
}
const string DMWindows40d::readSTLString (uint32_t offset)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
uint32_t length = g_pProcess->readDWord(offset + 20);
uint32_t capacity = g_pProcess->readDWord(offset + 24);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}
DfVector DMLinux40d::readVector (uint32_t offset, uint32_t item_size)
{
/*
GNU libstdc++ vector is three pointers long
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
*/
uint32_t start = g_pProcess->readDWord(offset);
uint32_t end = g_pProcess->readDWord(offset+4);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
struct _Rep_base
{
uint32_t _M_length;
uint32_t _M_capacity;
uint32_t _M_refcount;
};
size_t DMLinux40d::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
_Rep_base header;
offset = g_pProcess->readDWord(offset);
g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination
g_pProcess->read(offset,read_real,(uint8_t * )buffer);
buffer[read_real] = 0;
return read_real;
}
const string DMLinux40d::readSTLString (uint32_t offset)
{
_Rep_base header;
offset = g_pProcess->readDWord(offset);
g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
// FIXME: use char* everywhere, avoid string
char * temp = new char[header._M_length+1];
g_pProcess->read(offset,header._M_length+1,(uint8_t * )temp);
string ret(temp);
delete temp;
return ret;
}

@ -1,60 +0,0 @@
/*
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.
*/
#ifndef DATAMODEL_H_INCLUDED
#define DATAMODEL_H_INCLUDED
namespace DFHack
{
class DfVector;
// let's go pure virtual.
class DataModel
{
public:
// read a string
virtual const string readSTLString (uint32_t offset) = 0;
virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) = 0;
// read a vector from memory
//template <class T>
virtual DfVector readVector (uint32_t offset, uint32_t item_size) = 0;
};
class DMWindows40d : public DataModel
{
virtual const string readSTLString (uint32_t offset);
virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
// read a vector from memory
virtual DfVector readVector (uint32_t offset, uint32_t item_size);
};
class DMLinux40d : public DataModel
{
virtual const string readSTLString (uint32_t offset);
virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
// read a vector from memory
virtual DfVector readVector (uint32_t offset, uint32_t item_size);
};
}
#endif // DATAMODEL_H_INCLUDED

@ -30,7 +30,7 @@ class API::Private
public:
Private()
: block (NULL)
, pm (NULL), p (NULL), dm (NULL), offset_descriptor (NULL)
, pm (NULL), p (NULL), offset_descriptor (NULL)
, p_cons (NULL), p_bld (NULL), p_veg (NULL)
{}
uint32_t * block;
@ -87,7 +87,6 @@ public:
ProcessEnumerator* pm;
Process* p;
DataModel* dm;
memory_info* offset_descriptor;
vector<uint16_t> v_geology[eBiomeCount];
string xml;
@ -265,7 +264,7 @@ bool API::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer)
bool API::getCurrentCursorCreatures (vector<uint32_t> &addresses)
{
assert (d->cursorWindowInited);
DfVector creUnderCursor = d->dm->readVector (d->current_cursor_creature_offset, 4);
DfVector creUnderCursor = d->p->readVector (d->current_cursor_creature_offset, 4);
if (creUnderCursor.getSize() == 0)
{
return false;
@ -328,7 +327,7 @@ bool API::ReadVeins (uint32_t x, uint32_t y, uint32_t z, vector <t_vein> & veins
{
// veins are stored as a vector of pointers to veins
/*pointer is 4 bytes! we work with a 32bit program here, no matter what architecture we compile khazad for*/
DfVector p_veins = d->dm->readVector (addr + d->veinvector, 4);
DfVector p_veins = d->p->readVector (addr + d->veinvector, 4);
uint32_t size = p_veins.getSize();
veins.reserve (size);
@ -364,7 +363,7 @@ bool API::ReadWoodMatgloss (vector<t_matgloss> & woods)
int matgloss_address = d->offset_descriptor->getAddress ("matgloss");
int matgloss_wood_name_offset = d->offset_descriptor->getOffset("matgloss_wood_name");
// TODO: find flag for autumnal coloring?
DfVector p_matgloss = d->dm->readVector (matgloss_address, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address, 4);
woods.clear();
@ -380,10 +379,10 @@ bool API::ReadWoodMatgloss (vector<t_matgloss> & woods)
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
/*
fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
*/
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_wood_name_offset, mat.name, 128);
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_wood_name_offset, mat.name, 128);
woods.push_back (mat);
}
return true;
@ -397,7 +396,7 @@ bool API::ReadStoneMatgloss (vector<t_matgloss> & stones)
int matgloss_colors = minfo->getOffset ("matgloss_stone_color");
int matgloss_stone_name_offset = minfo->getOffset("matgloss_stone_name");
DfVector p_matgloss = d->dm->readVector (matgloss_address + matgloss_offset, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address + matgloss_offset, 4);
uint32_t size = p_matgloss.getSize();
stones.resize (0);
@ -408,9 +407,9 @@ bool API::ReadStoneMatgloss (vector<t_matgloss> & stones)
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
t_matgloss mat;
//fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_stone_name_offset, mat.name, 128);
//fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_stone_name_offset, mat.name, 128);
mat.fore = (uint8_t) g_pProcess->readWord (temp + matgloss_colors);
mat.back = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 2);
mat.bright = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 4);
@ -427,7 +426,7 @@ bool API::ReadMetalMatgloss (vector<t_matgloss> & metals)
int matgloss_offset = minfo->getHexValue ("matgloss_skip");
int matgloss_colors = minfo->getOffset ("matgloss_metal_color");
int matgloss_metal_name_offset = minfo->getOffset("matgloss_metal_name");
DfVector p_matgloss = d->dm->readVector (matgloss_address + matgloss_offset * 3, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address + matgloss_offset * 3, 4);
metals.clear();
@ -437,9 +436,9 @@ bool API::ReadMetalMatgloss (vector<t_matgloss> & metals)
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
t_matgloss mat;
//fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_metal_name_offset, mat.name, 128);
//fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_metal_name_offset, mat.name, 128);
mat.fore = (uint8_t) g_pProcess->readWord (temp + matgloss_colors);
mat.back = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 2);
mat.bright = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 4);
@ -454,7 +453,7 @@ bool API::ReadPlantMatgloss (vector<t_matgloss> & plants)
int matgloss_address = minfo->getAddress ("matgloss");
int matgloss_offset = minfo->getHexValue ("matgloss_skip");
int matgloss_plant_name_offset = minfo->getOffset("matgloss_plant_name");
DfVector p_matgloss = d->dm->readVector (matgloss_address + matgloss_offset * 2, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address + matgloss_offset * 2, 4);
plants.clear();
@ -468,9 +467,9 @@ bool API::ReadPlantMatgloss (vector<t_matgloss> & plants)
// read the matgloss pointer from the vector into temp
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
//fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128);
//fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128);
plants.push_back (mat);
}
return true;
@ -485,7 +484,7 @@ bool API::ReadPlantMatgloss (vector<t_matglossPlant> & plants)
int matgloss_plant_drink_offset = minfo->getOffset("matgloss_plant_drink");
int matgloss_plant_food_offset = minfo->getOffset("matgloss_plant_food");
int matgloss_plant_extract_offset = minfo->getOffset("matgloss_plant_extract");
DfVector p_matgloss = d->dm->readVector (matgloss_address + matgloss_offset * 2, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address + matgloss_offset * 2, 4);
plants.clear();
@ -499,14 +498,14 @@ bool API::ReadPlantMatgloss (vector<t_matglossPlant> & plants)
// read the matgloss pointer from the vector into temp
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
//fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128);
d->dm->readSTLString (temp+matgloss_plant_drink_offset, mat.drink_name, 128);
d->dm->readSTLString (temp+matgloss_plant_food_offset, mat.food_name, 128);
d->dm->readSTLString (temp+matgloss_plant_extract_offset, mat.extract_name, 128);
//fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_plant_name_offset, mat.name, 128);
d->p->readSTLString (temp+matgloss_plant_drink_offset, mat.drink_name, 128);
d->p->readSTLString (temp+matgloss_plant_food_offset, mat.food_name, 128);
d->p->readSTLString (temp+matgloss_plant_extract_offset, mat.extract_name, 128);
//d->dm->readSTLString (temp
//d->p->readSTLString (temp
plants.push_back (mat);
}
return true;
@ -518,7 +517,7 @@ bool API::ReadCreatureMatgloss (vector<t_matgloss> & creatures)
int matgloss_address = minfo->getAddress ("matgloss");
int matgloss_offset = minfo->getHexValue ("matgloss_skip");
int matgloss_creature_name_offset = minfo->getOffset("matgloss_creature_name");
DfVector p_matgloss = d->dm->readVector (matgloss_address + matgloss_offset * 6, 4);
DfVector p_matgloss = d->p->readVector (matgloss_address + matgloss_offset * 6, 4);
creatures.clear();
@ -532,9 +531,9 @@ bool API::ReadCreatureMatgloss (vector<t_matgloss> & creatures)
// read the matgloss pointer from the vector into temp
uint32_t temp = * (uint32_t *) p_matgloss[i];
// read the string pointed at by
//fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address
d->dm->readSTLString (temp, mat.id, 128);
d->dm->readSTLString (temp+matgloss_creature_name_offset, mat.name, 128);
//fill_char_buf(mat.id, d->p->readSTLString(temp)); // reads a C string given an address
d->p->readSTLString (temp, mat.id, 128);
d->p->readSTLString (temp+matgloss_creature_name_offset, mat.name, 128);
creatures.push_back (mat);
}
return true;
@ -587,7 +586,7 @@ bool API::ReadGeology (vector < vector <uint16_t> >& assign)
uint32_t regions = g_pProcess->readDWord (world_offset + world_regions_offset);
// read the geoblock vector
DfVector geoblocks = d->dm->readVector (world_offset + world_geoblocks_offset, 4);
DfVector geoblocks = d->p->readVector (world_offset + world_geoblocks_offset, 4);
// iterate over 8 surrounding regions + local region
for (int i = eNorthWest; i < eBiomeCount; i++)
@ -613,7 +612,7 @@ bool API::ReadGeology (vector < vector <uint16_t> >& assign)
uint32_t geoblock_off = * (uint32_t *) geoblocks[geoindex];
// get the vector with pointer to layers
DfVector geolayers = d->dm->readVector (geoblock_off + geolayer_geoblock_offset , 4); // let's hope
DfVector geolayers = d->p->readVector (geoblock_off + geolayer_geoblock_offset , 4); // let's hope
// make sure we don't load crap
assert (geolayers.getSize() > 0 && geolayers.getSize() <= 16);
@ -645,7 +644,7 @@ bool API::InitReadBuildings ( uint32_t& numbuildings )
if(buildings)
{
d->buildingsInited = true;
d->p_bld = new DfVector (d->dm->readVector (buildings, 4));
d->p_bld = new DfVector (d->p->readVector (buildings, 4));
return true;
}
else
@ -703,7 +702,7 @@ bool API::InitReadConstructions(uint32_t & numconstructions)
int constructions = d->offset_descriptor->getAddress ("constructions");
if(constructions)
{
d->p_cons = new DfVector (d->dm->readVector (constructions, 4));
d->p_cons = new DfVector (d->p->readVector (constructions, 4));
d->constructionsInited = true;
numconstructions = d->p_cons->getSize();
return true;
@ -753,7 +752,7 @@ bool API::InitReadVegetation(uint32_t & numplants)
if(vegetation && d->tree_offset)
{
d->vegetationInited = true;
d->p_veg = new DfVector (d->dm->readVector (vegetation, 4));
d->p_veg = new DfVector (d->p->readVector (vegetation, 4));
numplants = d->p_veg->getSize();
return true;
}
@ -840,7 +839,7 @@ bool API::InitReadCreatures( uint32_t &numcreatures )
// && d->creature_likes_offset
)
{
d->p_cre = new DfVector (d->dm->readVector (creatures, 4));
d->p_cre = new DfVector (d->p->readVector (creatures, 4));
//InitReadNameTables();
d->creaturesInited = true;
numcreatures = d->p_cre->getSize();
@ -925,11 +924,11 @@ bool API::ReadCreature (const int32_t &index, t_creature & furball)
g_pProcess->readDWord (temp + d->creature_flags1_offset, furball.flags1.whole);
g_pProcess->readDWord (temp + d->creature_flags2_offset, furball.flags2.whole);
// normal names
d->dm->readSTLString (temp + d->creature_first_name_offset, furball.first_name, 128);
d->dm->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128);
d->p->readSTLString (temp + d->creature_first_name_offset, furball.first_name, 128);
d->p->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128);
// custom profession
d->dm->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128);
fill_char_buf (furball.custom_profession, d->dm->readSTLString (temp + d->creature_custom_profession_offset));
d->p->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128);
fill_char_buf (furball.custom_profession, d->p->readSTLString (temp + d->creature_custom_profession_offset));
// crazy composited names
g_pProcess->read (temp + d->creature_last_name_offset, sizeof (t_lastname), (uint8_t *) &furball.last_name);
g_pProcess->read (temp + d->creature_squad_name_offset, sizeof (t_squadname), (uint8_t *) &furball.squad_name);
@ -941,7 +940,7 @@ bool API::ReadCreature (const int32_t &index, t_creature & furball)
// traits
g_pProcess->read (temp + d->creature_traits_offset, sizeof (uint16_t) * NUM_CREATURE_TRAITS, (uint8_t *) &furball.traits);
// learned skills
DfVector skills (d->dm->readVector (temp + d->creature_skills_offset, 4));
DfVector skills (d->p->readVector (temp + d->creature_skills_offset, 4));
furball.numSkills = skills.getSize();
for (uint32_t i = 0; i < furball.numSkills;i++)
{
@ -963,7 +962,7 @@ bool API::ReadCreature (const int32_t &index, t_creature & furball)
}
//likes
DfVector likes(d->dm->readVector(temp+d->creature_likes_offset,4));
DfVector likes(d->p->readVector(temp+d->creature_likes_offset,4));
furball.numLikes = likes.getSize();
for(uint32_t i = 0;i<furball.numLikes;i++)
{
@ -996,25 +995,25 @@ bool API::InitReadNameTables (map< string, vector<string> > & nameTable)
if(genericAddress && transAddress && word_table_offset)
{
DfVector genericVec (d->dm->readVector (genericAddress, 4));
DfVector transVec (d->dm->readVector (transAddress, 4));
DfVector genericVec (d->p->readVector (genericAddress, 4));
DfVector transVec (d->p->readVector (transAddress, 4));
for (uint32_t i = 0;i < genericVec.getSize();i++)
{
uint32_t genericNamePtr = * (uint32_t *) genericVec.at (i);
string genericName = d->dm->readSTLString (genericNamePtr);
string genericName = d->p->readSTLString (genericNamePtr);
nameTable["GENERIC"].push_back (genericName);
}
for (uint32_t i = 0; i < transVec.getSize();i++)
{
uint32_t transPtr = * (uint32_t *) transVec.at (i);
string transName = d->dm->readSTLString (transPtr);
DfVector trans_names_vec (d->dm->readVector (transPtr + word_table_offset, 4));
string transName = d->p->readSTLString (transPtr);
DfVector trans_names_vec (d->p->readVector (transPtr + word_table_offset, 4));
for (uint32_t j = 0;j < trans_names_vec.getSize();j++)
{
uint32_t transNamePtr = * (uint32_t *) trans_names_vec.at (j);
string name = d->dm->readSTLString (transNamePtr);
string name = d->p->readSTLString (transNamePtr);
nameTable[transName].push_back (name);
}
}
@ -1113,7 +1112,6 @@ bool API::Attach()
return false; // couldn't attach to process, no go
}
d->offset_descriptor = d->p->getDescriptor();
d->dm = d->p->getDataModel();
// process is attached, everything went just fine... hopefully
return true;
}
@ -1132,13 +1130,12 @@ bool API::Detach()
d->pm = NULL;
d->p = NULL;
d->offset_descriptor = NULL;
d->dm = NULL;
return true;
}
bool API::isAttached()
{
return d->dm != NULL;
return d->p != NULL;
}
bool API::Suspend()
@ -1290,7 +1287,7 @@ bool API::InitReadItems(uint32_t & numitems)
if(items && d->item_material_offset)
{
d->p_itm = new DfVector (d->dm->readVector (items, 4));
d->p_itm = new DfVector (d->p->readVector (items, 4));
d->itemsInited = true;
numitems = d->p_itm->getSize();
return true;
@ -1375,15 +1372,15 @@ bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes)
int matgloss_skip = minfo->getHexValue("matgloss_skip");
int item_type_name_offset = minfo->getOffset("item_type_name");
for(int i = 8;i<20;i++){
DfVector p_temp = d->dm->readVector(matgloss_address + i*matgloss_skip,4);
DfVector p_temp = d->p->readVector(matgloss_address + i*matgloss_skip,4);
vector< t_itemType > typesForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
t_itemType currType;
uint32_t temp = *(uint32_t *) p_temp[j];
// Mread(temp+40,sizeof(name),(uint8_t *) name);
d->dm->readSTLString(temp+4,currType.id,128);
d->dm->readSTLString(temp+item_type_name_offset,currType.name,128);
d->p->readSTLString(temp+4,currType.id,128);
d->p->readSTLString(temp+item_type_name_offset,currType.name,128);
//stringsForVec.push_back(string(name));
typesForVec.push_back(currType);
}
@ -1400,44 +1397,44 @@ bool API::ReadAllMatgloss(vector< vector< string > > & all)
int matgloss_address = minfo->getAddress("matgloss");
int matgloss_skip = minfo->getHexValue("matgloss_skip");
for(int i = 0;i<7;i++){
DfVector p_temp = d->dm->readVector(matgloss_address + i*matgloss_skip,4);
DfVector p_temp = d->p->readVector(matgloss_address + i*matgloss_skip,4);
vector< string > stringsForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
uint32_t temp = *(uint32_t *) p_temp[j];
string tempStr = d->dm->readSTLString(temp);
string tempStr = d->p->readSTLString(temp);
stringsForVec.push_back(tempStr);
}
all.push_back(stringsForVec);
}
for(int i = 7;i<22;i++){
DfVector p_temp = d->dm->readVector(matgloss_address + i*matgloss_skip,4);
DfVector p_temp = d->p->readVector(matgloss_address + i*matgloss_skip,4);
vector< string > stringsForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
uint32_t temp = *(uint32_t *) p_temp[j];
string tempStr = d->dm->readSTLString(temp+4);
string tempStr = d->p->readSTLString(temp+4);
stringsForVec.push_back(tempStr);
}
all.push_back(stringsForVec);
}
for(int i = 22;i<25;i++){
DfVector p_temp = d->dm->readVector(matgloss_address + i*matgloss_skip,4);
DfVector p_temp = d->p->readVector(matgloss_address + i*matgloss_skip,4);
vector< string > stringsForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
uint32_t temp = *(uint32_t *) p_temp[j];
string tempStr = d->dm->readSTLString(temp);
string tempStr = d->p->readSTLString(temp);
stringsForVec.push_back(tempStr);
}
all.push_back(stringsForVec);
}
DfVector p_temp = d->dm->readVector(0x01604104,4);
DfVector p_temp = d->p->readVector(0x01604104,4);
vector< string > stringsForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
uint32_t temp = *(uint32_t *) p_temp[j];
string tempStr = d->dm->readSTLString(temp);
string tempStr = d->p->readSTLString(temp);
stringsForVec.push_back(tempStr);
}
all.push_back(stringsForVec);

@ -40,7 +40,6 @@ class SHMProcess::Private
public:
Private()
{
my_datamodel = NULL;
my_descriptor = NULL;
my_pid = 0;
my_shm = 0;
@ -51,7 +50,6 @@ class SHMProcess::Private
identified = false;
};
~Private(){};
DataModel* my_datamodel;
memory_info * my_descriptor;
DFWindow * my_window;
pid_t my_pid;
@ -229,7 +227,6 @@ bool SHMProcess::Private::validate(char * exe_file, uint32_t pid, vector <memory
if(hash == (*it).getString("md5")) // are the md5 hashes the same?
{
memory_info * m = &*it;
my_datamodel = new DMLinux40d();
my_descriptor = m;
my_pid = pid;
identified = true;
@ -247,10 +244,6 @@ SHMProcess::~SHMProcess()
detach();
}
// destroy data model. this is assigned by processmanager
if(d->my_datamodel)
{
delete d->my_datamodel;
}
if(d->my_window)
{
delete d->my_window;
@ -262,12 +255,6 @@ SHMProcess::~SHMProcess()
delete d;
}
DataModel *SHMProcess::getDataModel()
{
return d->my_datamodel;
}
memory_info * SHMProcess::getDescriptor()
{
return d->my_descriptor;
@ -603,3 +590,50 @@ const std::string SHMProcess::readCString (uint32_t offset)
return temp;
}
DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size)
{
/*
GNU libstdc++ vector is three pointers long
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
*/
uint32_t start = g_pProcess->readDWord(offset);
uint32_t end = g_pProcess->readDWord(offset+4);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
const std::string SHMProcess::readSTLString(uint32_t offset)
{
((shm_read_small *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
//int length = ((shm_retval *)d->my_shm)->value;
return(string( (char *)d->my_shm+SHM_HEADER));
}
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
((shm_read_small *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
size_t length = ((shm_retval *)d->my_shm)->value;
size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,(char *)d->my_shm+SHM_HEADER,fit);
buffer[fit] = 0;
return fit;
}
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{
((shm_write_small *)d->my_shm)->address = address;
strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING;
d->waitWhile(DFPP_WRITE_STL_STRING);
}

@ -0,0 +1,584 @@
/*
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"
#include <errno.h>
#include <sys/ptrace.h>
using namespace DFHack;
class WineProcess::Private
{
public:
Private()
{
my_descriptor = NULL;
my_handle = NULL;
my_window = NULL;
my_pid = 0;
attached = false;
suspended = false;
memFileHandle = 0;
};
~Private(){};
DFWindow* my_window;
memory_info * my_descriptor;
ProcessHandle my_handle;
uint32_t my_pid;
string memFile;
int memFileHandle;
bool attached;
bool suspended;
bool identified;
bool validate(char * exe_file, uint32_t pid, char * mem_file, vector <memory_info> & known_versions);
};
WineProcess::WineProcess(uint32_t pid, vector <memory_info> & known_versions)
: d(new Private())
{
char dir_name [256];
char exe_link_name [256];
char mem_name [256];
char cwd_name [256];
char cmdline_name [256];
char target_name[1024];
int target_result;
d->identified = false;
sprintf(dir_name,"/proc/%d/", pid);
sprintf(exe_link_name,"/proc/%d/exe", pid);
sprintf(mem_name,"/proc/%d/mem", pid);
sprintf(cwd_name,"/proc/%d/cwd", pid);
sprintf(cmdline_name,"/proc/%d/cmdline", pid);
// resolve /proc/PID/exe link
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
if (target_result == -1)
{
return;
}
// make sure we have a null terminated string...
target_name[target_result] = 0;
// is this the regular linux DF?
if (strstr(target_name, "dwarfort.exe") != NULL)
{
// create linux process, add it to the vector
d->identified = d->validate(target_name,pid,mem_name,known_versions );
d->my_window = new DFWindow(this);
return;
}
// FIXME: this fails when the wine process isn't started from the 'current working directory'. strip path data from cmdline
// is this windows version of Df running in wine?
if(strstr(target_name, "wine-preloader")!= NULL)
{
// get working directory
target_result = readlink(cwd_name, target_name, sizeof(target_name)-1);
target_name[target_result] = 0;
// got path to executable, do the same for its name
ifstream ifs ( cmdline_name , ifstream::in );
string cmdline;
getline(ifs,cmdline);
if (cmdline.find("dwarfort-w.exe") != string::npos || cmdline.find("dwarfort.exe") != string::npos || cmdline.find("Dwarf Fortress.exe") != string::npos)
{
char exe_link[1024];
// put executable name and path together
sprintf(exe_link,"%s/%s",target_name,cmdline.c_str());
// create wine process, add it to the vector
d->identified = d->validate(exe_link,pid,mem_name,known_versions);
d->my_window = new DFWindow(this);
return;
}
}
}
bool WineProcess::isSuspended()
{
return d->suspended;
}
bool WineProcess::isAttached()
{
return d->attached;
}
bool WineProcess::isIdentified()
{
return d->identified;
}
bool WineProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector <memory_info> & known_versions)
{
md5wrapper md5;
// get hash of the running DF process
string hash = md5.getHashFromFile(exe_file);
vector<memory_info>::iterator it;
// iterate over the list of memory locations
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
// are the md5 hashes the same?
if(memory_info::OS_WINDOWS == (*it).getOS() && hash == (*it).getString("md5"))
{
memory_info * m = &*it;
my_descriptor = m;
my_handle = my_pid = pid;
// tell WineProcess about the /proc/PID/mem file
this->memFile = memFile;
identified = true;
return true;
}
}
return false;
}
WineProcess::~WineProcess()
{
if(d->attached)
{
detach();
}
if(d->my_window)
delete d->my_window;
delete d;
}
memory_info * WineProcess::getDescriptor()
{
return d->my_descriptor;
}
DFWindow * WineProcess::getWindow()
{
return d->my_window;
}
int WineProcess::getPID()
{
return d->my_pid;
}
//FIXME: implement
bool WineProcess::getThreadIDs(vector<uint32_t> & threads )
{
return false;
}
//FIXME: cross-reference with ELF segment entries?
void WineProcess::getMemRanges( vector<t_memrange> & ranges )
{
char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0
sprintf(buffer, "/proc/%lu/maps", d->my_pid);
FILE *mapFile = ::fopen(buffer, "r");
uint64_t offset, device1, device2, node;
while (fgets(buffer, 1024, mapFile))
{
t_memrange temp;
temp.name[0] = 0;
sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s",
&temp.start,
&temp.end,
(char*)&permissions,
&offset, &device1, &device2, &node,
(char*)&temp.name);
temp.read = permissions[0] == 'r';
temp.write = permissions[1] == 'w';
temp.execute = permissions[2] == 'x';
ranges.push_back(temp);
}
}
bool WineProcess::asyncSuspend()
{
return suspend();
}
bool WineProcess::suspend()
{
int status;
if(!d->attached)
return false;
if(d->suspended)
return true;
if (kill(d->my_handle, SIGSTOP) == -1)
{
// no, we got an error
perror("kill SIGSTOP error");
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(d->my_handle, &status, 0);
if (w == -1)
{
// child died
perror("DF exited during suspend call");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
d->suspended = true;
return true;
}
bool WineProcess::forceresume()
{
return resume();
}
bool WineProcess::resume()
{
if(!d->attached)
return false;
if(!d->suspended)
return true;
if (ptrace(PTRACE_CONT, d->my_handle, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace resume error");
return false;
}
d->suspended = false;
return true;
}
bool WineProcess::attach()
{
int status;
if(g_pProcess != NULL)
{
return false;
}
// can we attach?
if (ptrace(PTRACE_ATTACH , d->my_handle, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace attach error");
cerr << "attach failed on pid " << d->my_handle << endl;
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(d->my_handle, &status, 0);
if (w == -1)
{
// child died
perror("wait inside attach()");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
d->suspended = true;
int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY);
if(proc_pid_mem == -1)
{
ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL);
cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl;
perror("open(memFile.c_str(),O_RDONLY)");
return false;
}
else
{
d->attached = true;
g_pProcess = this;
d->memFileHandle = proc_pid_mem;
return true; // we are attached
}
}
bool WineProcess::detach()
{
if(!d->attached) return false;
if(!d->suspended) suspend();
int result = 0;
// close /proc/PID/mem
result = close(d->memFileHandle);
if(result == -1)
{
cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl;
perror("mem file close");
return false;
}
else
{
// detach
result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL);
if(result == -1)
{
cerr << "couldn't detach from process pid" << d->my_handle << endl;
perror("ptrace detach");
return false;
}
else
{
d->attached = false;
g_pProcess = NULL;
return true;
}
}
}
// danger: uses recursion!
void WineProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target)
{
if(size == 0) return;
ssize_t result;
result = pread(d->memFileHandle, target,size,offset);
if(result != size)
{
if(result == -1)
{
cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl;
cerr << "errno: " << errno << endl;
errno = 0;
}
else
{
read(offset + result, size - result, target + result);
}
}
}
uint8_t WineProcess::readByte (const uint32_t offset)
{
uint8_t val;
read(offset, 1, &val);
return val;
}
void WineProcess::readByte (const uint32_t offset, uint8_t &val )
{
read(offset, 1, &val);
}
uint16_t WineProcess::readWord (const uint32_t offset)
{
uint16_t val;
read(offset, 2, (uint8_t *) &val);
return val;
}
void WineProcess::readWord (const uint32_t offset, uint16_t &val)
{
read(offset, 2, (uint8_t *) &val);
}
uint32_t WineProcess::readDWord (const uint32_t offset)
{
uint32_t val;
read(offset, 4, (uint8_t *) &val);
return val;
}
void WineProcess::readDWord (const uint32_t offset, uint32_t &val)
{
read(offset, 4, (uint8_t *) &val);
}
/*
* WRITING
*/
void WineProcess::writeDWord (uint32_t offset, uint32_t data)
{
ptrace(PTRACE_POKEDATA,d->my_handle, offset, data);
}
// using these is expensive.
void WineProcess::writeWord (uint32_t offset, uint16_t data)
{
uint32_t orig = readDWord(offset);
orig &= 0xFFFF0000;
orig |= data;
/*
orig |= 0x0000FFFF;
orig &= data;
*/
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
}
void WineProcess::writeByte (uint32_t offset, uint8_t data)
{
uint32_t orig = readDWord(offset);
orig &= 0xFFFFFF00;
orig |= data;
/*
orig |= 0x000000FF;
orig &= data;
*/
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
}
// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS
void WineProcess::write (uint32_t offset, uint32_t size, uint8_t *source)
{
uint32_t indexptr = 0;
while (size > 0)
{
// default: we push 4 bytes
if(size >= 4)
{
writeDWord(offset, *(uint32_t *) (source + indexptr));
offset +=4;
indexptr +=4;
size -=4;
}
// last is either three or 2 bytes
else if(size >= 2)
{
writeWord(offset, *(uint16_t *) (source + indexptr));
offset +=2;
indexptr +=2;
size -=2;
}
// finishing move
else if(size == 1)
{
writeByte(offset, *(uint8_t *) (source + indexptr));
return;
}
}
}
const std::string WineProcess::readCString (uint32_t offset)
{
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = readByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r && counter < 255);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}
DfVector WineProcess::readVector (uint32_t offset, uint32_t item_size)
{
/*
MSVC++ vector is four pointers long
ptr allocator
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
we also don't care about the allocator thing in front
*/
uint32_t start = g_pProcess->readDWord(offset+4);
uint32_t end = g_pProcess->readDWord(offset+8);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
size_t length = g_pProcess->readDWord(offset + 20);
size_t capacity = g_pProcess->readDWord(offset + 24);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
}
const string WineProcess::readSTLString (uint32_t offset)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
uint32_t length = g_pProcess->readDWord(offset + 20);
uint32_t capacity = g_pProcess->readDWord(offset + 24);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}

@ -31,7 +31,6 @@ class NormalProcess::Private
public:
Private()
{
my_datamodel = NULL;
my_descriptor = NULL;
my_handle = NULL;
my_window = NULL;
@ -41,7 +40,6 @@ class NormalProcess::Private
memFileHandle = 0;
};
~Private(){};
DataModel* my_datamodel;
DFWindow* my_window;
memory_info * my_descriptor;
ProcessHandle my_handle;
@ -90,31 +88,6 @@ NormalProcess::NormalProcess(uint32_t pid, vector <memory_info> & known_versions
d->my_window = new DFWindow(this);
return;
}
// FIXME: this fails when the wine process isn't started from the 'current working directory'. strip path data from cmdline
// is this windows version of Df running in wine?
if(strstr(target_name, "wine-preloader")!= NULL)
{
// get working directory
target_result = readlink(cwd_name, target_name, sizeof(target_name)-1);
target_name[target_result] = 0;
// got path to executable, do the same for its name
ifstream ifs ( cmdline_name , ifstream::in );
string cmdline;
getline(ifs,cmdline);
if (cmdline.find("dwarfort-w.exe") != string::npos || cmdline.find("dwarfort.exe") != string::npos || cmdline.find("Dwarf Fortress.exe") != string::npos)
{
char exe_link[1024];
// put executable name and path together
sprintf(exe_link,"%s/%s",target_name,cmdline.c_str());
// create wine process, add it to the vector
d->identified = d->validate(exe_link,pid,mem_name,known_versions);
d->my_window = new DFWindow(this);
return;
}
}
}
bool NormalProcess::isSuspended()
@ -144,16 +117,8 @@ bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFi
if(hash == (*it).getString("md5")) // are the md5 hashes the same?
{
memory_info * m = &*it;
// df can run under wine on Linux
if(memory_info::OS_WINDOWS == (*it).getOS())
if (memory_info::OS_LINUX == (*it).getOS())
{
my_datamodel =new DMWindows40d();
my_descriptor = m;
my_handle = my_pid = pid;
}
else if (memory_info::OS_LINUX == (*it).getOS())
{
my_datamodel =new DMLinux40d();
my_descriptor = m;
my_handle = my_pid = pid;
}
@ -178,19 +143,11 @@ NormalProcess::~NormalProcess()
detach();
}
// destroy data model. this is assigned by processmanager
if(d->my_datamodel)
delete d->my_datamodel;
if(d->my_window)
delete d->my_window;
delete d;
}
DataModel *NormalProcess::getDataModel()
{
return d->my_datamodel;
}
memory_info * NormalProcess::getDescriptor()
{
return d->my_descriptor;
@ -522,3 +479,51 @@ const std::string NormalProcess::readCString (uint32_t offset)
return temp;
}
DfVector NormalProcess::readVector (uint32_t offset, uint32_t item_size)
{
/*
GNU libstdc++ vector is three pointers long
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
*/
uint32_t start = g_pProcess->readDWord(offset);
uint32_t end = g_pProcess->readDWord(offset+4);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
struct _Rep_base
{
uint32_t _M_length;
uint32_t _M_capacity;
uint32_t _M_refcount;
};
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
_Rep_base header;
offset = g_pProcess->readDWord(offset);
g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination
g_pProcess->read(offset,read_real,(uint8_t * )buffer);
buffer[read_real] = 0;
return read_real;
}
const string NormalProcess::readSTLString (uint32_t offset)
{
_Rep_base header;
offset = g_pProcess->readDWord(offset);
g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
// FIXME: use char* everywhere, avoid string
char * temp = new char[header._M_length+1];
g_pProcess->read(offset,header._M_length+1,(uint8_t * )temp);
string ret(temp);
delete temp;
return ret;
}

@ -31,7 +31,6 @@ class SHMProcess::Private
public:
Private()
{
my_datamodel = NULL;
my_descriptor = NULL;
my_pid = 0;
my_shm = 0;
@ -43,7 +42,6 @@ class SHMProcess::Private
DFCLMutex = 0;
};
~Private(){};
DataModel* my_datamodel;
memory_info * my_descriptor;
DFWindow * my_window;
uint32_t my_pid;
@ -153,122 +151,119 @@ SHMProcess::SHMProcess(vector <memory_info> & known_versions)
char exe_link_name [256];
char target_name[1024];
int target_result;
do
// get server and client mutex
d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, "DFSVMutex");
if(d->DFSVMutex == 0)
{
// get server and client mutex
d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, "DFSVMutex");
if(d->DFSVMutex == 0)
{
break;
}
d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, "DFCLMutex");
if(d->DFCLMutex == 0)
{
break;
}
if(!attach())
{
break;
}
// All seems to be OK so far. Attached and connected to something that looks like DF
return;
}
d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, "DFCLMutex");
if(d->DFCLMutex == 0)
{
return;
}
if(!attach())
{
return;
}
// All seems to be OK so far. Attached and connected to something that looks like DF
// Test bridge version, will also detect when we connect to something that doesn't respond
bool bridgeOK;
if(!d->DF_TestBridgeVersion(bridgeOK))
{
fprintf(stderr,"DF terminated during reading\n");
UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
return;
}
if(!bridgeOK)
{
fprintf(stderr,"SHM bridge version mismatch\n");
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
return;
}
/*
* get the PID from DF
*/
if(d->DF_GetPID(d->my_pid))
{
// try to identify the DF version
do // glorified goto
{
IMAGE_NT_HEADERS32 pe_header;
IMAGE_SECTION_HEADER sections[16];
HMODULE hmod = NULL;
DWORD junk;
HANDLE hProcess;
bool found = false;
d->identified = false;
// open process, we only need the process open
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->my_pid );
if (NULL == hProcess)
break;
// try getting the first module of the process
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0)
{
CloseHandle(hProcess);
cout << "EnumProcessModules fail'd" << endl;
break;
}
// got base ;)
uint32_t base = (uint32_t)hmod;
// read from this process
uint32_t pe_offset = readDWord(base+0x3C);
read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections );
// iterate over the list of memory locations
vector<memory_info>::iterator it;
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
uint32_t pe_timestamp = (*it).getHexValue("pe_timestamp");
if (pe_timestamp == pe_header.FileHeader.TimeDateStamp)
{
memory_info *m = new memory_info(*it);
m->RebaseAll(base);
d->my_descriptor = m;
d->identified = true;
cerr << "identified " << m->getVersion() << endl;
break;
}
}
CloseHandle(hProcess);
} while (0); // glorified goto end
// Test bridge version, will also detect when we connect to something that doesn't respond
bool bridgeOK;
if(!d->DF_TestBridgeVersion(bridgeOK))
if(d->identified)
{
fprintf(stderr,"DF terminated during reading\n");
UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
break;
d->my_window = new DFWindow(this);
}
if(!bridgeOK)
else
{
fprintf(stderr,"SHM bridge version mismatch\n");
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
UnmapViewOfFile(d->my_shm);
d->my_shm = 0;
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
break;
return;
}
/*
* get the PID from DF
*/
if(d->DF_GetPID(d->my_pid))
{
// try to identify the DF version
do // glorified goto
{
IMAGE_NT_HEADERS32 pe_header;
IMAGE_SECTION_HEADER sections[16];
HMODULE hmod = NULL;
DWORD junk;
HANDLE hProcess;
bool found = false;
d->identified = false;
// open process, we only need the process open
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->my_pid );
if (NULL == hProcess)
break;
// try getting the first module of the process
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0)
{
CloseHandle(hProcess);
cout << "EnumProcessModules fail'd" << endl;
break;
}
// got base ;)
uint32_t base = (uint32_t)hmod;
// read from this process
uint32_t pe_offset = readDWord(base+0x3C);
read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections );
// iterate over the list of memory locations
vector<memory_info>::iterator it;
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
uint32_t pe_timestamp = (*it).getHexValue("pe_timestamp");
if (pe_timestamp == pe_header.FileHeader.TimeDateStamp)
{
memory_info *m = new memory_info(*it);
m->RebaseAll(base);
d->my_datamodel = new DMWindows40d();
d->my_descriptor = m;
d->identified = true;
cerr << "identified " << m->getVersion() << endl;
break;
}
}
CloseHandle(hProcess);
} while (0); // glorified goto end
if(d->identified)
{
d->my_window = new DFWindow(this);
}
else
{
((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING;
UnmapViewOfFile(d->my_shm);
ReleaseMutex(d->DFCLMutex);
CloseHandle(d->DFSVMutex);
d->DFSVMutex = 0;
CloseHandle(d->DFCLMutex);
d->DFCLMutex = 0;
break;
}
}
} while (0);
}
full_barrier
// at this point, DF is attached and suspended, make it run
detach();
@ -295,10 +290,6 @@ SHMProcess::~SHMProcess()
detach();
}
// destroy data model. this is assigned by processmanager
if(d->my_datamodel)
{
delete d->my_datamodel;
}
if(d->my_descriptor)
{
delete d->my_descriptor;
@ -319,12 +310,6 @@ SHMProcess::~SHMProcess()
delete d;
}
DataModel *SHMProcess::getDataModel()
{
return d->my_datamodel;
}
memory_info * SHMProcess::getDescriptor()
{
return d->my_descriptor;
@ -686,3 +671,56 @@ const std::string SHMProcess::readCString (uint32_t offset)
return temp;
}
DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size)
{
/*
MSVC++ vector is four pointers long
ptr allocator
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
we also don't care about the allocator thing in front
*/
uint32_t start = g_pProcess->readDWord(offset+4);
uint32_t end = g_pProcess->readDWord(offset+8);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
const std::string SHMProcess::readSTLString(uint32_t offset)
{
//offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4
((shm_read_small *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
int length = ((shm_retval *)d->my_shm)->value;
// char temp_c[256];
// strncpy(temp_c, d->my_shm+SHM_HEADER,length+1); // length + 1 for the null terminator
return(string(d->my_shm+SHM_HEADER));
}
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
//offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4
((shm_read_small *)d->my_shm)->address = offset;
full_barrier
((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING;
d->waitWhile(DFPP_READ_STL_STRING);
size_t length = ((shm_retval *)d->my_shm)->value;
size_t real = min(length, bufcapacity - 1);
strncpy(buffer, d->my_shm+SHM_HEADER,real); // length + 1 for the null terminator
buffer[real] = 0;
return real;
}
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{
((shm_write_small *)d->my_shm)->address = address/*-4*/;
strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING;
d->waitWhile(DFPP_WRITE_STL_STRING);
}

@ -29,7 +29,6 @@ class NormalProcess::Private
public:
Private()
{
my_datamodel = NULL;
my_descriptor = NULL;
my_handle = NULL;
my_main_thread = NULL;
@ -39,7 +38,6 @@ class NormalProcess::Private
suspended = false;
};
~Private(){};
DataModel* my_datamodel;
memory_info * my_descriptor;
DFWindow * my_window;
ProcessHandle my_handle;
@ -109,7 +107,6 @@ NormalProcess::NormalProcess(uint32_t pid, vector <memory_info> & known_versions
// keep track of created memory_info object so we can destroy it later
d->my_descriptor = m;
// process is responsible for destroying its data model
d->my_datamodel = new DMWindows40d();
d->my_pid = pid;
d->my_handle = hProcess;
d->identified = true;
@ -142,8 +139,6 @@ NormalProcess::~NormalProcess()
{
detach();
}
// destroy data model. this is assigned by processmanager
delete d->my_datamodel;
// destroy our rebased copy of the memory descriptor
delete d->my_descriptor;
if(d->my_handle != NULL)
@ -161,13 +156,6 @@ NormalProcess::~NormalProcess()
delete d;
}
DataModel *NormalProcess::getDataModel()
{
return d->my_datamodel;
}
memory_info * NormalProcess::getDescriptor()
{
return d->my_descriptor;
@ -390,3 +378,89 @@ const string NormalProcess::readCString (const uint32_t offset)
return temp;
}
DfVector NormalProcess::readVector (uint32_t offset, uint32_t item_size)
{
/*
MSVC++ vector is four pointers long
ptr allocator
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
we also don't care about the allocator thing in front
*/
uint32_t start = g_pProcess->readDWord(offset+4);
uint32_t end = g_pProcess->readDWord(offset+8);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
}
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
size_t length = g_pProcess->readDWord(offset + 20);
size_t capacity = g_pProcess->readDWord(offset + 24);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
}
const string NormalProcess::readSTLString (uint32_t offset)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
uint32_t length = g_pProcess->readDWord(offset + 20);
uint32_t capacity = g_pProcess->readDWord(offset + 24);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset
g_pProcess->read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}

@ -30,9 +30,9 @@ distribution.
namespace DFHack
{
class memory_info;
class DataModel;
class Process;
class DFWindow;
class DfVector;
// structure describing a memory range
struct DFHACK_EXPORT t_memrange
@ -90,6 +90,13 @@ namespace DFHack
virtual void writeByte(const uint32_t address, const uint8_t value) = 0;
virtual void write(uint32_t address, uint32_t length, uint8_t* buffer) = 0;
// read a string
virtual const string readSTLString (uint32_t offset) = 0;
virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) = 0;
virtual void writeSTLString(const uint32_t address, const std::string writeString) = 0;
// read a vector from memory
virtual DfVector readVector (uint32_t offset, uint32_t item_size) = 0;
virtual const std::string readCString (uint32_t offset) = 0;
virtual bool isSuspended() = 0;
@ -103,8 +110,6 @@ namespace DFHack
// get the flattened Memory.xml entry of this process
virtual memory_info *getDescriptor() = 0;
// get the DataModel for reading stl containers (depends on the version of stl DF was compiled with)
virtual DataModel *getDataModel() = 0;
// get the DF's window (first that can be found ~_~)
virtual DFWindow * getWindow() = 0;
// get the DF Process ID
@ -142,6 +147,12 @@ namespace DFHack
void writeByte(const uint32_t address, const uint8_t value);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString){};
// read a vector from memory
DfVector readVector (uint32_t offset, uint32_t item_size);
const std::string readCString (uint32_t offset);
bool isSuspended();
@ -151,7 +162,6 @@ namespace DFHack
bool getThreadIDs(vector<uint32_t> & threads );
void getMemRanges( vector<t_memrange> & ranges );
memory_info *getDescriptor();
DataModel *getDataModel();
DFWindow * getWindow();
int getPID();
};
@ -183,11 +193,68 @@ namespace DFHack
void readByte(const uint32_t address, uint8_t & value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void writeDWord(const uint32_t address, const uint32_t value);
void writeWord(const uint32_t address, const uint16_t value);
void writeByte(const uint32_t address, const uint8_t value);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString);
// read a vector from memory
DfVector readVector (uint32_t offset, uint32_t item_size);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(vector<uint32_t> & threads );
void getMemRanges( vector<t_memrange> & ranges );
memory_info *getDescriptor();
DFWindow * getWindow();
int getPID();
};
#ifdef LINUX_BUILD
class DFHACK_EXPORT WineProcess : virtual public Process
{
friend class ProcessEnumerator;
class Private;
private:
Private * const d;
public:
WineProcess(uint32_t pid, vector <memory_info> & known_versions);
~WineProcess();
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
uint32_t readDWord(const uint32_t address);
void readDWord(const uint32_t address, uint32_t & value);
uint16_t readWord(const uint32_t address);
void readWord(const uint32_t address, uint16_t & value);
uint8_t readByte(const uint32_t address);
void readByte(const uint32_t address, uint8_t & value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void writeDWord(const uint32_t address, const uint32_t value);
void writeWord(const uint32_t address, const uint16_t value);
void writeByte(const uint32_t address, const uint8_t value);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
void writeSTLString(const uint32_t address, const std::string writeString){};
// read a vector from memory
DfVector readVector (uint32_t offset, uint32_t item_size);
const std::string readCString (uint32_t offset);
bool isSuspended();
@ -197,9 +264,9 @@ namespace DFHack
bool getThreadIDs(vector<uint32_t> & threads );
void getMemRanges( vector<t_memrange> & ranges );
memory_info *getDescriptor();
DataModel *getDataModel();
DFWindow * getWindow();
int getPID();
};
#endif
}
#endif

@ -76,11 +76,22 @@ bool ProcessEnumerator::findProcessess()
if(p2->isIdentified())
{
d->processes.push_back(p2);
continue;
}
else
{
delete p2;
}
Process *p3 = new WineProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo);
if(p3->isIdentified())
{
d->processes.push_back(p3);
continue;
}
else
{
delete p3;
}
}
closedir(dir_p);
// return value depends on if we found some DF processes

@ -103,6 +103,7 @@ bool ProcessEnumerator::findProcessess()
else
{
delete q;
q = 0;
}
}
if(d->processes.size())

@ -32,7 +32,6 @@ class TiXmlElement;
namespace DFHack
{
class memory_info;
class DataModel;
class Process;
/*

@ -29,6 +29,7 @@ distribution.
#include "../library/integers.h"
#include <stdlib.h>
#include <string.h>
#include <string>
//#include <unistd.h>
#include "shms.h"
// various crud
@ -45,6 +46,7 @@ void SHM_Act (void)
uint32_t numwaits = 0;
uint32_t length;
uint32_t address;
std::string * myStringPtr;
check_again: // goto target!!!
SCHED_YIELD // yield the CPU, valid only on single-core CPUs
if(numwaits == 10000)
@ -69,6 +71,7 @@ void SHM_Act (void)
case DFPP_RET_DWORD:
case DFPP_RET_WORD:
case DFPP_RET_BYTE:
case DFPP_RET_STRING:
case DFPP_SUSPENDED:
case DFPP_RET_PID:
case DFPP_SV_ERROR:
@ -159,21 +162,22 @@ void SHM_Act (void)
//MessageBox(0,"Broke out of loop properly","FUN", MB_OK);
break;
// client requests contents of STL string at address
/*case DFPP_READ_STL_STRING:
char * real = *(char **)((shm_read_small *)shm)->address;
strncpy(shm + SHM_HEADER,real,1024*1024-1);
case DFPP_READ_STL_STRING:
myStringPtr = (std::string *) ((shm_read_small *)shm)->address;
((shm_retval *)shm)->value = myStringPtr->length();
strncpy(shm+SHM_HEADER,myStringPtr->c_str(),myStringPtr->length()+1);// length + 1 for the null terminator
full_barrier
((shm_retval *)shm)->pingpong = DFPP_RET_STRING;
goto check_again;
*/
// client requests contents of a C string at address, max length (0 means zero terminated)
/* case DFPP_READ_C_STRING:
break;
// sv -> cl length + string contents
// client wants to set STL string at address to something
case DFPP_WRITE_STL_STRING:
break;*/
myStringPtr = (std::string *) ((shm_write *)shm)->address;
myStringPtr->assign((const char *) (shm + SHM_HEADER));
full_barrier
((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED;
goto check_again;
default:
((shm_retval *)shm)->value = DFEE_INVALID_COMMAND;
full_barrier

@ -1,7 +1,7 @@
#ifndef DFCONNECT_H
#define DFCONNECT_H
#define PINGPONG_VERSION 1
#define PINGPONG_VERSION 2
#define SHM_KEY 123466
#define SHM_HEADER 1024
#define SHM_BODY 1024*1024
@ -139,6 +139,13 @@ typedef struct
uint32_t value;
} shm_retval;
typedef struct
{
volatile uint32_t pingpong;
uint32_t length;
} shm_retstr;
void SHM_Act (void);
bool isValidSHM();
uint32_t getPID();

@ -10,13 +10,15 @@ using namespace std;
#include <DFTypes.h>
#include <DFHackAPI.h>
#include <DFMemInfo.h>
#include <DFProcess.h>
template <typename T>
void print_bits ( T val, std::ostream& out )
{
T n_bits = sizeof ( val ) * CHAR_BIT;
for ( unsigned i = 0; i < n_bits; ++i ) {
for ( unsigned i = 0; i < n_bits; ++i )
{
out<< !!( val & 1 ) << " ";
val >>= 1;
}
@ -28,26 +30,30 @@ vector<DFHack::t_matgloss> creaturestypes;
void printDwarves(DFHack::API & DF)
{
int dwarfCounter = 0;
for(uint32_t i = 0; i < numCreatures; i++)
for (uint32_t i = 0; i < numCreatures; i++)
{
DFHack::t_creature temp;
DF.ReadCreature(i, temp);
string type = creaturestypes[temp.type].id;
if(type == "DWARF" && !temp.flags1.bits.dead && !temp.flags2.bits.killed){
if (type == "DWARF" && !temp.flags1.bits.dead && !temp.flags2.bits.killed)
{
cout << i << ":";
if(temp.nick_name[0])
if (temp.nick_name[0])
{
cout << temp.nick_name;
}
else{
else
{
cout << temp.first_name;
}
string transName = DF.TranslateName(temp.last_name,names,creaturestypes[temp.type].id);
cout << " " << temp.custom_profession; //transName;
if(dwarfCounter%3 != 2){
if (dwarfCounter%3 != 2)
{
cout << '\t';
}
else{
else
{
cout << endl;
}
dwarfCounter++;
@ -59,29 +65,29 @@ bool getDwarfSelection(DFHack::API & DF, DFHack::t_creature & toChange,string &
{
static string lastText;
bool dwarfSuccess = false;
while(!dwarfSuccess)
while (!dwarfSuccess)
{
string input;
cout << "\nSelect Dwarf to Change or q to Quit" << endl;
DF.Resume();
getline (cin, input);
DF.Suspend();
if(input == "q")
if (input == "q")
{
return false;
}
else if(input == "r")
else if (input == "r")
{
printDwarves(DF);
}
else if(!input.empty())
else if (!input.empty())
{
int num;
stringstream(input) >> num;//= atol(input.c_str());
dwarfSuccess = DF.ReadCreature(num,toChange);
string type = creaturestypes[toChange.type].id;
if(type != "DWARF")
if (type != "DWARF")
{
dwarfSuccess = false;
}
@ -92,21 +98,24 @@ bool getDwarfSelection(DFHack::API & DF, DFHack::t_creature & toChange,string &
}
}
bool changeType = false;
while(!changeType)
while (!changeType)
{
string input;
cout << "\n(n)ickname or (p)rofession?" << endl;
getline(cin, input);
if(input == "q"){
if (input == "q")
{
return false;
}
if(input == "n"){
if (input == "n")
{
commandString = "pzyn";
eraseAmount = string(toChange.nick_name).length();
changeType = true;
isName = true;
}
else if(input == "p"){
else if (input == "p")
{
commandString = "pzyp";
eraseAmount = string(toChange.custom_profession).length();
changeType = true;
@ -114,18 +123,21 @@ bool getDwarfSelection(DFHack::API & DF, DFHack::t_creature & toChange,string &
}
}
bool changeValue = false;
while(!changeValue)
while (!changeValue)
{
string input;
cout << "value to change to?" << endl;
getline(cin, input);
if(input == "q"){
if (input == "q")
{
return false;
}
if(!lastText.empty() && input.empty()){
if (!lastText.empty() && input.empty())
{
changeValue = true;
}
else if( !input.empty()){
else if ( !input.empty())
{
lastText = input;
changeValue = true;
}
@ -140,9 +152,9 @@ bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, b
DFHack::t_creature testCre;
DF.ReadCreature(creatureToCheck,testCre);
int tryCount = 0;
if(isName)
if (isName)
{
while(testCre.nick_name != changeValue && tryCount <50)
while (testCre.nick_name != changeValue && tryCount <50)
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -153,7 +165,7 @@ bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, b
}
else
{
while(testCre.custom_profession != changeValue && tryCount < 50)
while (testCre.custom_profession != changeValue && tryCount < 50)
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -162,13 +174,16 @@ bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, b
tryCount++;
}
}
if(tryCount >= 50){
if (tryCount >= 50)
{
cerr << "Something went wrong, make sure that DF is at the correct screen";
return false;
}
DF.Resume();
return true;
}
bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true)
{
DFHack::DFWindow * w = DF.getWindow();
@ -176,7 +191,7 @@ bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true)
DF.Suspend();
DF.ReadViewScreen(current);
int tryCount = 0;
while(((EqualTo && objecttypes[current.type] != screenState) || (!EqualTo && objecttypes[current.type] == screenState)) && tryCount < 50)
while (((EqualTo && objecttypes[current.type] != screenState) || (!EqualTo && objecttypes[current.type] == screenState)) && tryCount < 50)
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -184,7 +199,7 @@ bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true)
DF.ReadViewScreen(current);
tryCount++;
}
if(tryCount >= 50){
if (tryCount >= 50) {
cerr << "Something went wrong, DF at " << objecttypes[current.type] << endl;
return false;
}
@ -192,6 +207,7 @@ bool waitTillScreenState(DFHack::API &DF, string screenState,bool EqualTo=true)
return true;
}
bool waitTillCursorState(DFHack::API &DF, bool On)
{
DFHack::DFWindow * w = DF.getWindow();
@ -199,7 +215,7 @@ bool waitTillCursorState(DFHack::API &DF, bool On)
int tryCount = 0;
DF.Suspend();
bool cursorResult = DF.getCursorCoords(x,y,z);
while(tryCount < 50 && On && !cursorResult || !On && cursorResult)
while (tryCount < 50 && On && !cursorResult || !On && cursorResult)
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -207,7 +223,7 @@ bool waitTillCursorState(DFHack::API &DF, bool On)
DF.Suspend();
cursorResult = DF.getCursorCoords(x,y,z);
}
if(tryCount >= 50)
if (tryCount >= 50)
{
cerr << "Something went wrong, cursor at x: " << x << " y: " << y << " z: " << z << endl;
return false;
@ -215,13 +231,15 @@ bool waitTillCursorState(DFHack::API &DF, bool On)
DF.Resume();
return true;
}
bool waitTillMenuState(DFHack::API &DF, uint32_t menuState,bool EqualTo=true)
{
int tryCount = 0;
DFHack::DFWindow * w = DF.getWindow();
DF.Suspend();
uint32_t testState = DF.ReadMenuState();
while(tryCount < 50 && ((EqualTo && menuState != testState) || (!EqualTo && menuState == testState)))
while (tryCount < 50 && ((EqualTo && menuState != testState) || (!EqualTo && menuState == testState)))
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
@ -229,7 +247,7 @@ bool waitTillMenuState(DFHack::API &DF, uint32_t menuState,bool EqualTo=true)
DF.Suspend();
testState = DF.ReadMenuState();
}
if(tryCount >= 50)
if (tryCount >= 50)
{
cerr << "Something went wrong, menuState: "<<testState << endl;
return false;
@ -237,28 +255,32 @@ bool waitTillMenuState(DFHack::API &DF, uint32_t menuState,bool EqualTo=true)
DF.Resume();
return true;
}
bool moveToBaseWindow(DFHack::API &DF)
{
DFHack::DFWindow * w = DF.getWindow();
DFHack::t_viewscreen current;
DF.ReadViewScreen(current);
while(objecttypes[current.type] != string("viewscreen_dwarfmode"))
while (objecttypes[current.type] != string("viewscreen_dwarfmode"))
{
w->TypeSpecial(DFHack::F9); // cancel out of text input in names
// DF.TypeSpecial(DFHack::ENTER); // cancel out of text input in hotkeys
w->TypeSpecial(DFHack::SPACE); // should move up a level
if(!waitTillScreenState(DF,objecttypes[current.type],false)) return false; // wait until screen changes from current
if (!waitTillScreenState(DF,objecttypes[current.type],false)) return false; // wait until screen changes from current
DF.ReadViewScreen(current);
}
if(DF.ReadMenuState() != 0){// if menu state != 0 then there is a menu, so escape it
w->TypeSpecial(DFHack::F9);w->TypeSpecial(DFHack::ENTER); // exit out of any text prompts
if (DF.ReadMenuState() != 0) {// if menu state != 0 then there is a menu, so escape it
w->TypeSpecial(DFHack::F9);
w->TypeSpecial(DFHack::ENTER); // exit out of any text prompts
w->TypeSpecial(DFHack::SPACE); // go back to base state
if(!waitTillMenuState(DF,0))return false;
if (!waitTillMenuState(DF,0))return false;
}
DF.Resume();
return true;
}
bool setCursorToCreature(DFHack::API &DF)
{
DFHack::DFWindow * w = DF.getWindow();
@ -266,125 +288,158 @@ bool setCursorToCreature(DFHack::API &DF)
DF.Suspend();
DF.getCursorCoords(x,y,z);
DF.Resume();
if(x == -30000){
if (x == -30000) {
w->TypeStr("v");
if(!waitTillCursorState(DF,true)) return false;
if (!waitTillCursorState(DF,true)) return false;
}
else{ // reset the cursor to be the creature cursor
else { // reset the cursor to be the creature cursor
w->TypeSpecial(DFHack::SPACE);
if(!waitTillCursorState(DF,false)) return false;
if (!waitTillCursorState(DF,false)) return false;
w->TypeStr("v");
if(!waitTillCursorState(DF,true)) return false;
if (!waitTillCursorState(DF,true)) return false;
}
return true;
}
int main (void)
{
{
DFHack::API DF("Memory.xml");
if(!DF.Attach())
if (!DF.Attach())
{
cerr << "DF not found" << endl;
return 1;
}
DF.Suspend();
if(!DF.getClassIDMapping(objecttypes))
if (!DF.getClassIDMapping(objecttypes))
{
cerr << "Can't get type info" << endl;
return 1;
}
DFHack::memory_info mem = DF.getMemoryInfo();
if(!DF.ReadCreatureMatgloss(creaturestypes))
if (!DF.ReadCreatureMatgloss(creaturestypes))
{
cerr << "Can't get the creature types." << endl;
return 1;
return 1;
}
DF.InitReadNameTables(names);
DF.InitReadCreatures(numCreatures);
DF.InitViewAndCursor();
printDwarves(DF);
DFHack::Process * p = DF.getProcess();
DFHack::DFWindow * w = DF.getWindow();
DFHack::t_creature toChange;
string changeString,commandString;
int eraseAmount;
int toChangeNum;
bool isName;
DFHack::DFWindow * w = DF.getWindow();
while(getDwarfSelection(DF,toChange,changeString,commandString,eraseAmount,toChangeNum,isName))
bool useKeys = true;
string input2;
// use key event emulation or direct writing?
cout << "\nUse \n1:Key simulation\n2:Direct Writing" << endl;
getline(cin,input2);
if (input2 == "1")
{
useKeys = true;
}
else {
useKeys = false;
}
printDwarves(DF);
while (getDwarfSelection(DF,toChange,changeString,commandString,eraseAmount,toChangeNum,isName))
{
// limit length, DF doesn't accept input after this point
if(changeString.size() > 39)
if (changeString.size() > 39)
{
changeString.resize(39);
}
start:
start:
bool completed = false;
if(moveToBaseWindow(DF) && setCursorToCreature(DF))
{
DF.Suspend();
DF.setCursorCoords(toChange.x, toChange.y,toChange.z);
vector<uint32_t> underCursor;
while(!DF.getCurrentCursorCreatures(underCursor))
if (useKeys) {
if (moveToBaseWindow(DF) && setCursorToCreature(DF))
{
DF.Resume();
w->TypeSpecial(DFHack::WAIT,1,100);
DF.Suspend();
DF.setCursorCoords(toChange.x, toChange.y,toChange.z);
DF.ReadCreature(toChangeNum,toChange);
}
//CurrentCursorCreatures gives the creatures in the order that you see them with the 'k' cursor.
//The 'v' cursor displays them in the order of last, then first,second,third and so on
//Pretty weird, but it works
//The only place that seems to display which creature is currently selected is on the stack, whose location is likely not static, so not usable
if(underCursor[underCursor.size()-1] != toChange.origin)
{
for(int i = 0;i<underCursor.size()-1;i++)
vector<uint32_t> underCursor;
while (!DF.getCurrentCursorCreatures(underCursor))
{
DF.Resume();
w->TypeStr("v",100);
if(underCursor[i] == toChange.origin)
w->TypeSpecial(DFHack::WAIT,1,100);
DF.Suspend();
DF.setCursorCoords(toChange.x, toChange.y,toChange.z);
DF.ReadCreature(toChangeNum,toChange);
}
//CurrentCursorCreatures gives the creatures in the order that you see them with the 'k' cursor.
//The 'v' cursor displays them in the order of last, then first,second,third and so on
//Pretty weird, but it works
//The only place that seems to display which creature is currently selected is on the stack, whose location is likely not static, so not usable
if (underCursor[underCursor.size()-1] != toChange.origin)
{
for (int i = 0;i<underCursor.size()-1;i++)
{
break;
DF.Resume();
w->TypeStr("v",100);
if (underCursor[i] == toChange.origin)
{
break;
}
}
}
}
DF.Resume();
w->TypeStr(commandString.c_str());
if(waitTillScreenState(DF,"viewscreen_customize_unit"))
{
DF.Resume();
w->TypeSpecial(DFHack::BACK_SPACE,eraseAmount);
if(waitTillChanged(DF,toChangeNum,"",isName))
w->TypeStr(commandString.c_str());
if (waitTillScreenState(DF,"viewscreen_customize_unit"))
{
DF.Resume();
w->TypeStr(changeString.c_str());
if(waitTillChanged(DF,toChangeNum,changeString,isName))
w->TypeSpecial(DFHack::BACK_SPACE,eraseAmount);
if (waitTillChanged(DF,toChangeNum,"",isName))
{
DF.Resume();
w->TypeSpecial(DFHack::ENTER);
w->TypeSpecial(DFHack::SPACE); // should take you to unit screen if everything worked
if(waitTillScreenState(DF,"viewscreen_unit"))
w->TypeStr(changeString.c_str());
if (waitTillChanged(DF,toChangeNum,changeString,isName))
{
DF.Resume();
w->TypeSpecial(DFHack::SPACE);
if(waitTillScreenState(DF,"viewscreen_dwarfmode"))
w->TypeSpecial(DFHack::ENTER);
w->TypeSpecial(DFHack::SPACE); // should take you to unit screen if everything worked
if (waitTillScreenState(DF,"viewscreen_unit"))
{
DF.Resume();
w->TypeSpecial(DFHack::SPACE);
if(waitTillCursorState(DF,false))
if (waitTillScreenState(DF,"viewscreen_dwarfmode"))
{
completed = true;
DF.Resume();
w->TypeSpecial(DFHack::SPACE);
if (waitTillCursorState(DF,false))
{
completed = true;
}
}
}
}
}
}
}
if (!completed) {
cerr << "Something went wrong, please reset DF to its original state, then press any key to continue" << endl;
goto start;
}
}
if(!completed){
cerr << "Something went wrong, please reset DF to its original state, then press any key to continue" << endl;
goto start;
else
{
// will only work with the shm probably should check for it, but I don't know how,
// I have the writeString function do nothing for normal mode
if (commandString == "pzyn") // change nickname
{
p->writeSTLString(toChange.origin+mem.getOffset("creature_nick_name"),changeString);
}
else
{
p->writeSTLString(toChange.origin+mem.getOffset("creature_custom_profession"),changeString);
}
}
DF.Suspend();
printDwarves(DF);

@ -91,7 +91,7 @@ int main ()
return EXIT_FAILURE;
}
items_vector = new DFHack::DfVector (proc->getDataModel()->readVector (items, 4));
items_vector = new DFHack::DfVector (proc->readVector (items, 4));
for(uint32_t i = 0; i < items_vector->getSize(); i++)
{
// get pointer to object