diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 5f2dd3230..12de11fbd 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -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 ) diff --git a/library/DFCommonInternal.h b/library/DFCommonInternal.h index 9fd0dd0c0..1a98f8274 100644 --- a/library/DFCommonInternal.h +++ b/library/DFCommonInternal.h @@ -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" diff --git a/library/DFDataModel.cpp b/library/DFDataModel.cpp deleted file mode 100644 index 1e48a0bf5..000000000 --- a/library/DFDataModel.cpp +++ /dev/null @@ -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; -} diff --git a/library/DFDataModel.h b/library/DFDataModel.h deleted file mode 100644 index 479e8bb5e..000000000 --- a/library/DFDataModel.h +++ /dev/null @@ -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 - 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 diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp index 9a4d70219..bb53bb904 100644 --- a/library/DFHackAPI.cpp +++ b/library/DFHackAPI.cpp @@ -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 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 &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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 >& 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 >& 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 > & 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; jdm->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; jdm->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; jdm->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; jdm->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; jdm->readSTLString(temp); + string tempStr = d->p->readSTLString(temp); stringsForVec.push_back(tempStr); } all.push_back(stringsForVec); diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 1f1650f9d..3c729f790 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -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 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); +} \ No newline at end of file diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp new file mode 100644 index 000000000..24cc71cc8 --- /dev/null +++ b/library/DFProcess-linux-wine.cpp @@ -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 +#include +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 & known_versions); +}; + +WineProcess::WineProcess(uint32_t pid, vector & 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 & known_versions) +{ + md5wrapper md5; + // get hash of the running DF process + string hash = md5.getHashFromFile(exe_file); + vector::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 & threads ) +{ + return false; +} + +//FIXME: cross-reference with ELF segment entries? +void WineProcess::getMemRanges( vector & 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; +} \ No newline at end of file diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 31d4c72de..5bda864a6 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -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 & 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; +} \ No newline at end of file diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index fe58802ea..bccca900c 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -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 & 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 *)§ions ); + + // iterate over the list of memory locations + vector::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 *)§ions ); - - // iterate over the list of memory locations - vector::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); +} \ No newline at end of file diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index 87c934c96..f1780f474 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -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 & 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; +} \ No newline at end of file diff --git a/library/DFProcess.h b/library/DFProcess.h index 4ce46d50e..19acbbecd 100644 --- a/library/DFProcess.h +++ b/library/DFProcess.h @@ -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 & threads ); void getMemRanges( vector & 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 & threads ); + void getMemRanges( vector & 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 & 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 & threads ); void getMemRanges( vector & ranges ); memory_info *getDescriptor(); - DataModel *getDataModel(); DFWindow * getWindow(); int getPID(); }; +#endif } #endif diff --git a/library/DFProcessEnumerator-linux.cpp b/library/DFProcessEnumerator-linux.cpp index c9e20da70..321d151f0 100644 --- a/library/DFProcessEnumerator-linux.cpp +++ b/library/DFProcessEnumerator-linux.cpp @@ -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 diff --git a/library/DFProcessEnumerator-windows.cpp b/library/DFProcessEnumerator-windows.cpp index 94ffd5b7e..ac11d2ea2 100644 --- a/library/DFProcessEnumerator-windows.cpp +++ b/library/DFProcessEnumerator-windows.cpp @@ -103,6 +103,7 @@ bool ProcessEnumerator::findProcessess() else { delete q; + q = 0; } } if(d->processes.size()) diff --git a/library/DFProcessEnumerator.h b/library/DFProcessEnumerator.h index 601ac7f41..eeeca9041 100644 --- a/library/DFProcessEnumerator.h +++ b/library/DFProcessEnumerator.h @@ -32,7 +32,6 @@ class TiXmlElement; namespace DFHack { class memory_info; - class DataModel; class Process; /* diff --git a/shmserver/shms-proto.cpp b/shmserver/shms-proto.cpp index 8ea698524..25b5810c9 100644 --- a/shmserver/shms-proto.cpp +++ b/shmserver/shms-proto.cpp @@ -29,6 +29,7 @@ distribution. #include "../library/integers.h" #include #include +#include //#include #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 diff --git a/shmserver/shms.h b/shmserver/shms.h index 01f59a9d6..6da1322cb 100644 --- a/shmserver/shms.h +++ b/shmserver/shms.h @@ -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(); diff --git a/tools/customCreatureNameProf.cpp b/tools/customCreatureNameProf.cpp index 5f16626fe..9171d0eaf 100644 --- a/tools/customCreatureNameProf.cpp +++ b/tools/customCreatureNameProf.cpp @@ -10,13 +10,15 @@ using namespace std; #include #include #include +#include template 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 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: "<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 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; + 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;iTypeStr("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); diff --git a/tools/dfbauxite.cpp b/tools/dfbauxite.cpp index 79bacaeba..a08c01441 100644 --- a/tools/dfbauxite.cpp +++ b/tools/dfbauxite.cpp @@ -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