develop
Erik Youngren 2011-02-24 02:07:15 -08:00
commit 4dd5718c06
87 changed files with 7875 additions and 3892 deletions

2
.gitignore vendored

@ -29,3 +29,5 @@ dfhack/python/pydfhack/_pydfhack.so
dfhack/python/PyDFHack.egg-info
dfhack/python/build
dfhack/python/dist
/cmakeall.bat

@ -29,7 +29,7 @@ SET( DATA_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/output CACHE PATH "Output directory fo
OPTION(BUILD_DFHACK_DOCUMENTATION "Create doxygen documentation for developers" OFF)
OPTION(BUILD_DFHACK_EXAMPLES "Build example tools" OFF)
OPTION(BUILD_DFHACK_PLAYGROUND "Build tools from the playground folder" OFF)
OPTION(BUILD_DFHACK_C_BINDIGS "Build the C portion of the library" ON)
OPTION(BUILD_DFHACK_C_BINDINGS "Build the C portion of the library" ON)
OPTION(BUILD_OFFSET_EDITOR "Build the Offset GUI editor (not ready for use)." OFF)
OPTION(BUILD_DFHACK_SUPPORTED "Build the supported toold." ON)
OPTION(BUILD_DFHACK_SHM "Build the SHM." OFF)

@ -1,4 +1,6 @@
www.sourceforge.net/projects/dfhack
----------------------------------------------------------------------
License of dfhack
github.com/peterix/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
@ -19,3 +21,120 @@ must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
----------------------------------------------------------------------
License of library/include/dfhack/DFstdint_win.h
ISO C9x compliant stdint.h for Microsoft Visual Studio
Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
Copyright (c) 2006-2008 Alexander Chemeris
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------
License of argstream (used by some utilities for parsing command line params)
Copyright (C) 2004 Xavier Decoret <Xavier.Decoret@imag.fr>
argsteam is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Foobar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
This library is used by:
tools/playground/catsplosion.cpp
tools/playground/digger.cpp
tools/supported/vdig.cpp
----------------------------------------------------------------------------
License of "RSA Data Security, Inc. MD5 Message-Digest Algorithm"
Used to identify DF binaries.
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
-----------------------------------------------------------------
License of the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" C++ wrapper:
This is my wrapper-class to create
a MD5 Hash from a string and a file.
This code is completly free, you
can copy it, modify it, or do
what ever you want with it.
Feb. 2005
Benjamin Grüdelbach
------------------------------------------------------------------
License of the used XML reader library
www.sourceforge.net/projects/tinyxml
Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
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.

@ -1,5 +1,5 @@
mkdir build-real
cd build-real
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Debug
mingw32-make
mkdir build-real
cd build-real
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Debug
mingw32-make
pause

@ -1,6 +1,6 @@
mkdir build-real
cd build-real
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release --trace > trace-stdout.txt 2> trace-stderr.txt
mingw32-make 2> log.txt
pause
mkdir build-real
cd build-real
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release --trace > trace-stdout.txt 2> trace-stderr.txt
mingw32-make 2> log.txt
pause
dir file.xxx

@ -1,5 +1,5 @@
mkdir build-real
cd build-real
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release
mingw32-make 2> log.txt
mkdir build-real
cd build-real
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release
mingw32-make 2> log.txt
pause

@ -1,4 +1,4 @@
mkdir build-real
cd build-real
cmake ..\.. -G"Visual Studio 8 2005"
mkdir build-real
cd build-real
cmake ..\.. -G"Visual Studio 8 2005"
pause

@ -1,4 +1,4 @@
mkdir build-real
cd build-real
cmake ..\.. -G"Visual Studio 9 2008"
mkdir build-real
cd build-real
cmake ..\.. -G"Visual Studio 9 2008"
pause

@ -1,4 +1,4 @@
mkdir build-real
cd build-real
cmake ..\.. -G"Visual Studio 10"
mkdir build-real
cd build-real
cmake ..\.. -G"Visual Studio 10"
pause

@ -664,6 +664,10 @@
<class name="building_civzonest"/><!-- zone -->
<class name="building_actualst"/>
<class name="buildingst"/>
<class name="building_slabst" />
<class name="building_nestst" />
<class name="building_nest_boxst" />
<class name="building_hivest" />
</VTable>
<Offsets>
<Address name="WORLD" description="A huge object that many things in DF are part of. Contains the whole game and can be used as a base
@ -1470,13 +1474,21 @@
<Address name="screen_tiles_pointer" value="0x18313D0" />
</Group>
<Group name="World">
<Address name="current_weather" value="0x14BCDEE" />
<Address name="current_tick" value="0xde8910" /> MAYBE
<Address name="current_year" value="0xec78b0" />
<!--<Address name="current_weather" value="0x14BCDEE" />-->
</Group>
</Offsets>
</Version>
<Version name="v0.31.13 SDL" os="windows" base="DF2010">
<MD5 value="59f194b0b2103ca5df7601a01ce21280" />
<PETimeStamp value="0x4C90ADA8" />
<VTable>
<multiclass name="building_trapst" typeoffset="0xF8" />
<multiclass name="building_workshopst" typeoffset="0xF8" />
<multiclass name="building_furnacest" typeoffset="0x10A" />
<multiclass name="building_siegeenginest" typeoffset="0xF8" />
</VTable>
<Offsets>
<Address name="WORLD" value="0x016425A0" />
<Group name="vector">
@ -1500,7 +1512,11 @@
<Offset name="capacity" value="0x14" />
</Group>
</Group>
0x01482874 - current race
<Group name="name">
<Offset name="first" value="0x0" />
<Offset name="nick" value="0x1C" />
<Offset name="second_words" value="0x38" />
</Group>
<Group name="Position">
<Address name="cursor_xyz" value="0xac77f0" />
<Address name="window_x" value="0xe42c74" />
@ -1513,7 +1529,7 @@
<Address name="pause_state" value="0x147E971" />
</Group>
<Group name="World">
<Address name="current_weather" value="0x147E948" />
<Address name="current_weather" value="0x147E948" />
</Group>
<Group name="Vegetation">
<Address name="vector" value="0x1656EFC" />
@ -1536,15 +1552,15 @@
<Address name="world_size_y" value="0x1699292" />
<Group name="block">
<Offset name="vein_vector" value="0x08" />
<Offset name="feature_local" value="0x24 0x2C" />
<Offset name="feature_global" value="0x28 0x30" />
<Offset name="type" value="0x7A 0x009A" />
<Offset name="designation" value="0x27C 0x029C" />
<Offset name="occupancy" value="0x67C 0x069c" />
<Offset name="temperature1" value="0x157C 0x159c" />
<Offset name="temperature2" value="0x177C 0x179c" />
<Offset name="biome_stuffs" value="0x1D7C 0x1D9C" />
<Offset name="pathfinding" value="0x0D7c 0x0D9c" />
<Offset name="feature_local" value="0x24" />
<Offset name="feature_global" value="0x28" />
<Offset name="type" value="0x7A" />
<Offset name="designation" value="0x27C" />
<Offset name="occupancy" value="0x67C" />
<Offset name="temperature1" value="0x157C" />
<Offset name="temperature2" value="0x177C" />
<Offset name="biome_stuffs" value="0x1D7C" />
<Offset name="pathfinding" value="0x0D7c" />
</Group>
<Group name="features">
<Group name="global">
@ -1618,24 +1634,383 @@
<Address name="translation_vector" value="0x169a11C"/>
<Offset name="word_table" value="0x3c"/>
</Group>
<Group name="Creatures">
<Address name="vector" value="0x01655fe4"/>
<Address name="current_race" value="0x1482874" />
<Address name="current_civ" value="0x1482868" />
<Group name="creature">
<Offset name="name" value="0x0" />
<Offset name="custom_profession" value="0x006C" />
<Offset name="profession" value="0x0088" />
<Offset name="race" value="0x008C" />
<Offset name="position" value="0x90" />
<Offset name="flags1" value="0x00E0" />
<Offset name="flags2" value="0x00E4" />
<Offset name="caste" value="0x00F8"/>
<Offset name="sex" value="0x00FA" /> <!-- ASSUMED -->
<Offset name="id" value="0x00FC" />
<Offset name="civ" value="0x108" />
<Group name="advanced">
<Offset name="pickup_equipment_bit" value="0x01BC" />
<Offset name="mood" value="0x210" />
<Offset name="pregnancy" value="0x214" />
<Offset name="pregnancy_ptr" value="0x218" />
<Offset name="birth_year" value="0x220" />
<Offset name="birth_time" value="0x224" />
<Offset name="inventory_vector" value="0x284" />
<Offset name="current_job" value="0x02F0" />
<Offset name="current_job_skill" value="0x02F4" />
<Offset name="physical" value="0x3C4" />
<Offset name="appearance_vector" value="0x524" />
<Offset name="artifact_name" value="0x5D4" />
<Offset name="soul_vector" value="0x640" />
<Offset name="current_soul" value="0x650" />
<Offset name="labors" value="0x0664" />
<Offset name="happiness" value="0x0704" />
</Group>
</Group>
<Group name="soul">
<Offset name="name" value="0x4" />
<Offset name="mental" value="0x88" />
<Offset name="skills_vector" value="0x1F4 0x01F0" />
<Offset name="traits" value="0x0214" /> is it a vector?
</Group>
<Group name="job">
<Offset name="id" value="0x08" />
<!--
<Offset name="type" description="seems to be just like the old occupations" />
<Offset name="materials_vector" />
<Group name="material">
<Offset name="maintype" description="like mood materials, 0=bars, 4=stone, 5=wood, 57=cloth, 54=leather ..." />
<Offset name="sectype1" description="subsubtype ?" />
<Offset name="sectype2" description="subtype ?" />
<Offset name="sectype3" description="index of material (for example, 2 is for silver)" />
<Offset name="flags" description="set only for shell / bone mood requirements ?" />
</Group>
-->
</Group>
</Group>
<Group name="Vegetation">
<Address name="vector" value="0x1656efc"/>
<Offset name="tree_desc_offset" value="0x6C"/>
</Group>
<Group name="Buildings">
<Address name="buildings_vector" value="0x1656890"/>
Second possible: 0x16568a0 (can't decide)
<Offset name="building_custom_workshop_type" value="0x11C" />
<Offset name="custom_workshop_name" value="0x4" />
<Offset name="custom_workshop_type" value="0x20" />
<Address name="custom_workshop_vector" value="0x0169fB6C" /> Second possible: 0x0169fb7C
</Group>
</Offsets>
</Version>
<Version name="v0.31.14 SDL" os="windows" base="v0.31.13 SDL" rebase="0x1000">
<PETimeStamp value="0x4C9B6EFB" />
<MD5 value="2da156d1fbaf8192ede9ce91abc5f366" />
<Offsets>
<Group name="Maps">
<Group name="features">
<Group name="global">
<Address name="vector" value="0x169a8ec 0x16998e0" />
</Group>
<Group name="local">
<Address name="start_ptr" value="0x169a980 0x1699974" />
</Group>
</Group>
<Group name="geology">
<Address name="geoblock_vector" value="0x169a90C" />
<Address name="ptr2_region_array" value="0x169a93C" />
</Group>
</Group>
<Group name="Translations">
<Address name="language_vector" value="0x169b108 0x169b0fc"/>
<Address name="translation_vector" value="0x169b128 0x169b11c"/>
</Group>
<Group name="Materials">
<Address name="inorganics" value="0x169af24 0x1699f18 0x16BD0B0" />
<Address name="organics_all" value="0x169af34 0x1699f28 0x16BD0C8" />
<Address name="organics_trees" value="0x169af64 0x1699f58 0x16bd110" />
<Address name="organics_plants" value="0x169af44 0x1699f38 0x16bd0e0" />
<Address name="creature_type_vector" value="0x169b008 0x1699ffC 0x16BD204" />
<!--<Address name="other" value="0x16C647C" /> NO!-->
<Group name="descriptors">
<Address name="colors_vector" value="0x16a0b38 0x169fb2c" />
<Address name="all_colors_vector" value="0x16a0b58 0x169fb4c" />
</Group>
</Group>
<Group name="Buildings">
<Address name="custom_workshop_vector" value="0x016A0B78" /> Second possible: 0x016a0b88
</Group>
</Offsets>
</Version>
<Version name="v0.31.15 SDL" os="windows" base="v0.31.14 SDL">
<PETimeStamp value="0x4CA869EA" />
<MD5 value="b4d188dfb592fc813dad31f45407991d" />
</Version>
<Version name="v0.31.16 SDL" os="windows" base="v0.31.15 SDL" rebase="0x1050">
<PETimeStamp value="0x4CA9D544" />
<MD5 value="702b3ebaae468f73eb1411af54863013" />
<Offsets>
<Group name="Materials">
<Address name="other" value="0x16A21FC"/> 0x16445F0 + 0x5DC0C see code at 0x9CFB01
</Group>
<Group name="Creatures">
<Address name="current_civ" value="0x1484868 0x14848b8" />
<Address name="current_race" value="0x1484874 0x14848c4" />
</Group>
<Group name="Position">
<Address name="cursor_xyz" value="0xac97f0 0xac9840" />
<!--<Address name="screen_tiles_pointer" value="0x14826d4" />--> AS BOGUS AS IT GETS
<Address name="window_dims" value="0xaca07c 0xaca0cc" />
<Address name="window_x" value="0xE44C74 0xe44cc4" />
<Address name="window_y" value="0xE72D48 0xe72d98" />
<Address name="window_z" value="0xe72d24 0xe72d74" />
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x1480971" />
</Group>
<Group name="World">
<Address name="current_tick" value="0xdac470" /> MAYBE
<Address name="current_year" value="0xe8b410" />
<Address name="current_weather" value="0x1480948" />
</Group>
<Group name="Items">
<Address name="items_vector" value="0x16580d8" />
<Offset name="item_type_accessor" value="0x0" />
<Offset name="item_subtype_accessor" value="0x4" />
<Offset name="item_subindex_accessor" value="0x8" />
<Offset name="item_index_accessor" value="0xC" />
<Offset name="item_quality_accessor" value="0x238" />
<Offset name="item_improvement_vector" value="0x90" />
</Group>
</Offsets>
</Version>
<Version name="v0.31.18 SDL" os="windows" base="v0.31.16 SDL" rebase="0x492D0">
<PETimeStamp value="0x4CE2841D" />
<MD5 value="b7be6b9db369d6adb72319dcf780f9f5" />
<Offsets>
<Address name="WORLD" valid="false" />
<Group name="Buildings">
<Address name="buildings_vector" value="0x16a1be0" />
<Address name="custom_workshop_vector" value="0x16eaca0" />
<!--
<Offset name="building_custom_workshop_type"/>
<Address name="custom_workshop_vector"/>
<Offset name="custom_workshop_name"/>
<Offset name="custom_workshop_type"/>
<Offset name="building_custom_workshop_type" value="0x11c" /> INVALID!
<Offset name="custom_workshop_name" value="0x4" /> INVALID!
<Offset name="custom_workshop_type" value="0x20" /> INVALID!
-->
</Group>
<Group name="Position" valid="false">
<Address name="cursor_xyz" value="0xb127f0" valid="true" />
<Address name="window_dims" value="0xb1307c" valid="true" />
<Address name="window_x" value="0xe8dee4" valid="true" />
<Address name="window_y" value="0xebbfb8" valid="true" />
<Address name="window_z" value="0xebbf94" valid="true" />
</Group>
<Group name="GUI" valid="false">
<Address name="pause_state" value="0x14c9be1" valid="true" />
</Group>
<Group name="Maps">
<Group name="features">
<Group name="global">
<Address name="vector" value="0x16e4c30" />
</Group>
<Group name="local">
<Address name="start_ptr" value="0x16e4cc4" />
</Group>
</Group>
<Group name="geology">
<Address name="geoblock_vector" value="0x16E4C50" />
<Address name="ptr2_region_array" value="0x16E4C80" />
</Group>
</Group>
<Group name="Creatures" valid="false" >
0x016a12c0 vector
</Group>
<Group name="Materials" valid="false" >
<Address name="creature_type_vector" value="0x16E533C" valid="true" /> MAYBE... THE DETAILS WILL BE DIFFERENT
<Address name="inorganics" value="0x16e527C" valid="true" />
<!--<Address name="inorganics_gems?" value="0x16e528C" valid="true" />--> WTF IS THIS, I DON'T EVEN...
<Address name="organics_all" value="0x16e529C" valid="true" />
<Address name="organics_plants" value="0x16e52AC" valid="true" />
<Address name="organics_trees" value="0x16e52CC" valid="true" />
</Group>
<Group name="Constructions">
<Address name="vector" value="0x168d930"/>
</Group>
<Group name="Translations">
<Address name="language_vector" value="0x016e553c"/>
<Address name="translation_vector" value="0x016e551c"/>
</Group>
<!--
<Group name="Vegetation" valid="false">
<Address name="vector"/>
<Offset name="tree_desc_offset" valid="true"/>
</Group>
-->
<Group name="Items" valid="false">
<!-- most of those seem completely unused! -->
<Address name="items_vector" />
List of offsets in the VTable :
<Offset name="item_type_accessor" />
<Offset name="item_subtype_accessor" />
<Offset name="item_subindex_accessor" />
<Offset name="item_index_accessor" />
<Offset name="item_quality_accessor" />
<Offset name="item_improvement_vector" />
<Offset name="item_improvement_subindex" />
<Offset name="item_improvement_index" />
<Offset name="item_improvement_quality" />
<Offset name="item_type_accessor" /> (in the vtable)
</Group>
<Group name="World" valid="false">
<Address name="current_tick" description="Current time of the year" />
<Address name="current_year" description="Current year" />
<Address name="current_weather" value="0x14c9bb8" valid="true" />
</Group>
</Offsets>
</Version>
<Version name="v0.31.19 SDL" os="windows" base="v0.31.18 SDL">
<PETimeStamp value="0x4D5BC345" />
<MD5 value="b7d1ff74835e5e8220a7e81e31f5a28d" />
<Offsets valid="false">
<Group name="string" valid="true" />
<Group name="vector" valid="true" />
<Group name="name" valid="true" />
<Group name="Position" valid="false">
<Address name="cursor_xyz" value="0xb4a7f0" valid="true" />
<Address name="window_dims" value="0xb4b07c" valid="true" />
<Address name="window_x" value="0xec6984" valid="true" />
<Address name="window_y" value="0xef4ba0" valid="true" />
<Address name="window_z" value="0xef4b7c" valid="true" />
</Group>
<Group name="Maps" valid="true">
<Address name="map_data" value="0x171C128" />
<Address name="x_count_block" value="0x171c140" />
<Address name="y_count_block" value="0x171c144" />
<Address name="z_count_block" value="0x171c148" />
<Address name="x_count" value="0x171c14C" />
<Address name="y_count" value="0x171c150" />
<Address name="z_count" value="0x171c154" />
<Address name="region_x" value="0x171c158" />
<Address name="region_y" value="0x171c15C" />
<Address name="region_z" value="0x171c160" /> TODO: it's signed!
<Address name="world_size_x" value="0x171d7e4" />
<Address name="world_size_y" value="0x171d7e6" />
<Group name="block">
<Offset name="vein_vector" value="0x8" />
<Offset name="feature_global" value="0x28" />
<Offset name="feature_local" value="0x24" />
<Offset name="type" value="0x7a" />
<Offset name="designation" value="0x27c" />
<Offset name="occupancy" value="0x67c" />
<Offset name="pathfinding" value="0xd7c" />
<Offset name="temperature1" value="0x157c" />
<Offset name="temperature2" value="0x177c" /><!-- looks strange, possibly invalid -->
<Offset name="biome_stuffs" value="0x1d7c" /><!-- possibly invalid -->
</Group>
<Group name="features">
<Group name="global">
<Address name="vector" value="0x171de84" />
<Offset name="funcptr" value="0xd8" />
<Offset name="material" value="0x2c" />
<Offset name="submaterial" value="0x30" />
</Group>
<Group name="local">
<Address name="start_ptr" value="0x171df18" />
<Offset name="material" value="0x28" />
<Offset name="submaterial" value="0x2c" />
</Group>
</Group>
<Group name="geology"> LOOKS FINE?
<Address name="geoblock_vector" value="0x171dea4" />
<Address name="ptr2_region_array" value="0x171ded4" /> VERIFIED
<Offset name="geolayer_geoblock_offset" value="0x4" />
<Offset name="region_geo_index_off" value="0x58" /> VERIFIED
<Offset name="type_inside_geolayer" value="0x4" />
<HexValue name="region_size" value="0x5c" /> VERIFIED
</Group>
</Group>
<Group name="Materials" valid="false" >
<Address name="creature_type_vector" value="0x171e880" valid="true" />
<Address name="inorganics" value="0x171e790" valid="true" />
<Address name="organics_all" value="0x171e7B0" valid="true" />
<Address name="organics_plants" value="0x171e7C0" valid="true" />
<Address name="organics_trees" value="0x171e7E0" valid="true" />
</Group>
<Group name="GUI" valid="false">
<Address name="pause_state" value="0x14c9be1" valid="true" />
</Group>
<Group name="Vegetation" valid="true">
<Address name="vector" value="0x16db478" />
</Group>
<Group name="Constructions" valid="true">
<Address name="vector" value="0x16c6ae8" />
</Group>
<Group name="Buildings" valid="true">
<Address name="buildings_vector" value="0x16dad78" valid="true" />
One of those really. Which one is the right one?
0x16dad78
0x16dad88
<Address name="custom_workshop_vector" value="0x1724204" valid="true" />
Let's assume those didn't change...
<!--
<Offset name="building_custom_workshop_type" value="0x11c" /> INVALID?
<Offset name="custom_workshop_name" value="0x4" /> INVALID?
<Offset name="custom_workshop_type" value="0x20" /> INVALID?
-->
</Group>
<Group name="World" valid="false">
<Address name="current_tick" description="Current time of the year" />
<Address name="current_year" description="Current year" />
<Address name="current_weather" value="0x15027A0" valid="true" />
</Group>
<!--
<Address name="WORLD" valid="false" />
<Group name="Maps">
<Group name="features">
<Group name="global">
<Address name="vector" value="0x16e4c30" />
</Group>
<Group name="local">
<Address name="start_ptr" value="0x16e4cc4" />
</Group>
</Group>
<Group name="geology">
<Address name="geoblock_vector" value="0x16E4C50" />
<Address name="ptr2_region_array" value="0x16E4C80" />
</Group>
</Group>
<Group name="Creatures" valid="false" >
0x016a12c0 vector
</Group>
<Group name="Translations">
<Address name="language_vector" value="0x016e553c"/>
<Address name="translation_vector" value="0x016e551c"/>
</Group>
<Group name="Items" valid="false">
<Address name="items_vector" />
List of offsets in the VTable :
<Offset name="item_type_accessor" />
<Offset name="item_subtype_accessor" />
<Offset name="item_subindex_accessor" />
<Offset name="item_index_accessor" />
<Offset name="item_quality_accessor" />
<Offset name="item_improvement_vector" />
<Offset name="item_improvement_subindex" />
<Offset name="item_improvement_index" />
<Offset name="item_improvement_quality" />
<Offset name="item_type_accessor" /> (in the vtable)
</Group>
-->
</Offsets>
</Version>
.-"""-.
' \
|,. ,-. | _________________________
@ -1662,7 +2037,7 @@
<MD5 value="fea3801a26538b1741f3cc9294139fca" />
<Offsets>
<Address name="WORLD" value="0x92C60E0" valid="false" />
<Group name="vector" valid="true">
<Group name="vector">
<HexValue name="sizeof" value="0xC" />
<Offset name="start" value="0x0" />
<!--
@ -1672,10 +2047,10 @@
DWORD AllocationEnd
-->
</Group>
<Group name="string" valid="true">
<Group name="string">
<HexValue name="sizeof" value="0x4" />
</Group>
<Group name="name" valid="true">
<Group name="name">
<Offset name="first" value="0x0" />
<Offset name="nick" value="0x4" />
<Offset name="second_words" value="0x8" />
@ -1703,7 +2078,7 @@
<Address name="region_z" value="0x9318D74" />
<Address name="world_size_x" value="0x931A3C0" />
<Address name="world_size_y" value="0x931A3C2" />
<Group name="block" valid="true">
<Group name="block">
<Offset name="vein_vector" value="0x08" />
<Offset name="feature_local" value="0x20" />
<Offset name="feature_global" value="0x24" />
@ -1743,7 +2118,7 @@
<Address name="vector" value="0x92D9AC0" />
<Address name="current_race" value="0x92C1628" />
<Address name="current_civ" value="0x92C161C" />
<Group name="creature" valid="verify" >
<Group name="creature">
<Offset name="name" value="0x0" />
<Offset name="custom_profession" value="0x3c" />
<Offset name="profession" value="0x40" />
@ -1801,7 +2176,7 @@
<Address name="organics_plants" value="0x931aea0" /><!-- plant matter, WORLD + 0x54BAC -->
<Address name="organics_trees" value="0x931aeb8" /><!-- just wood, WORLD + 0x54BDC -->
<Address name="creature_type_vector" value="0x931af34" /><!-- creature types, WORLD + 0x54CD0 -->
<Group name="creature" valid="verify">
<Group name="creature"> VERIFY
<Offset name="caste_vector" value="0x60" />
<Offset name="extract_vector" value="0x18f4" />
<Offset name="tile" value="0x20" />
@ -1876,15 +2251,15 @@
<MD5 value="4f1f988bc1b425d4193d3d8b7b0579a5" />
<Offsets>
<Group name="Creatures">
<Group name="creature" valid="verify" >
<Group name="creature"> VERIFY
<Group name="advanced">
<Offset name="soul_vector" value="0x0524" />
<Offset name="current_soul" value="0x0530" valid="verify" />
<Offset name="current_soul" value="0x0530" />
<Offset name="labors" value="0x540" />
<Offset name="happiness" value="0x5d0" />
</Group>
</Group>
<Group name="soul" valid="verify">
<Group name="soul">
<Offset name="name" value="0x0" />
<Offset name="mental" value="0x88" />
<Offset name="skills_vector" value="0x1C4" /> CHMOD
@ -1995,11 +2370,76 @@
<Address name="window_z" value="0x8ceb240" />
<Address name="cursor_xyz" value="0x8b2e740" />
<Address name="window_dims" value="0x8b2ec48" />
<Address name="screen_tiles_pointer" invalid = "true" />
<Address name="screen_tiles_pointer" valid = "false" />
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x92e0e90"/>
</Group>
<Group name="Vegetation">
<Address name="vector" value="0x92fbdc8" />
</Group>
<Group name="World">
<Address name="current_year" value="0x92e0da0" />
<Address name="current_tick" value="0x92e0dc0" />
<Address name="current_weather" value="0x092E0D84" />
</Group>
</Offsets>
</Version>
<Version name="v0.31.14 linux" os="linux" base="v0.31.13 linux" rebase="0x330C">
<MD5 value="128c562c7936aa8f84786f69426f0691" />
<Offsets>
<Group name="Maps">
<Address name="map_data" value="0x933d7e0" />
<Address name="x_count_block" value="0x933d7F4" />
<Address name="y_count_block" value="0x933d7F8" />
<Address name="z_count_block" value="0x933d7FC" />
<Address name="x_count" value="0x933d800" />
<Address name="y_count" value="0x933d804" />
<Address name="z_count" value="0x933d808" />
<Address name="region_x" value="0x933d80C" />
<Address name="region_y" value="0x933d810" />
<Address name="region_z" value="0x933d814" />
<Address name="world_size_x" value="0x933ee60" />
<Address name="world_size_y" value="0x933ee62" />
<Group name="features">
<Group name="global">
<Address name="vector" value="0x933f408" />0x933c0fc
</Group>
<Group name="local">
<Address name="start_ptr" value="0x933F480" />
</Group>
</Group>
<Group name="geology">
<Address name="geoblock_vector" value="0x933f420" />
<Address name="ptr2_region_array" value="0x933f444" />
</Group>
</Group>
<Group name="Buildings">
<Address name="buildings_vector" value="0x92febdc 0x92fb8e8" /> Alt:0x92febe8
</Group>
<Group name="Constructions">
<Address name="vector" value="0x92eac04 0x92e7904" />
</Group>
<!--
<Group name="Creatures">
<Address name="current_civ" value="0x92e2d9c" />
<Address name="current_race" value="0x92e2da8" />
<Address name="vector" value="0x92fb260" />
</Group>
-->
<Group name="Position">
<Address name="window_x" value="0x8cee538 0x8ceb238" />
<Address name="window_y" value="0x8cee53C 0x8ceb23C" />
<Address name="window_z" value="0x8cee540 0x8ceb240" />
<Address name="cursor_xyz" value="0x8b31a30 0x8b2e740" />
<Address name="window_dims" value="0x8b31f48 0x8b2ec48" />
<Address name="screen_tiles_pointer" valid = "false" />
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x92e0e90"/>
</Group>
<!--
<Group name="Vegetation">
<Address name="vector" value="0x92fbdc8" />
</Group>
@ -2008,6 +2448,133 @@
<Address name="current_tick" value="0x92e0dc0" />
<Address name="current_weather" value="0x092E0D84" />
</Group>
-->
</Offsets>
</Version>
<Version name="faek" os="linux" base="v0.31.14 linux">
<Offsets>
<Group name="Position" valid="false" />
</Offsets>
</Version>
<Version name="v0.31.16 linux" os="linux" base="faek" rebase="0x1b40">
<MD5 value="9cca2fa5da509e2f9a1042ddd1f9669c" />
<Offsets>
<Group name="Position">
<Address name="cursor_xyz" value="0x8b33550" />
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x92e5cb0"/>
</Group>
</Offsets>
</Version>
<Version name="v0.31.18 linux" os="linux" base="faek">
<MD5 value="884f794d8e89e7d764057c15617c20b1" />
<Offsets valid="false">
<Group name="Maps" valid="true">
<Address name="map_data" value="0x93c0430" />
<Address name="region_x" value="0x93c045c" />
<Address name="region_y" value="0x93c0460" />
<Address name="region_z" value="0x93c0464" />
<Address name="x_count_block" value="0x93c0444" />
<Address name="y_count_block" value="0x93c0448" />
<Address name="z_count_block" value="0x93c044c" />
<Address name="x_count" value="0x93c0450" />
<Address name="y_count" value="0x93c0454" />
<Address name="z_count" value="0x93c0458" />
<Address name="world_size_x" value="0x93c1ab0" />
<Address name="world_size_y" value="0x93c1ab2" />
<Group name="block" valid="true" />
<Group name="features" valid="false" />
<Group name="geology" valid="false" />
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x9366cb0"/>
</Group>
<Group name="string" valid="true" />
<Group name="vector" valid="true" />
<Group name="name" valid="true" />
</Offsets>
</Version>
<Version name="v0.31.19 linux" os="linux" base="v0.31.18 linux" rebase="0x77738">
<MD5 value="8fcb1f10af9cc2bda47d2acf42e1db54" />
<Offsets>
<Group name="Position">
<Address name="cursor_xyz" value="0x8c2b560" />
<Address name="window_dims" value="0x8ba9680" />
<Address name="window_x" value="0x8d65c70" />
<Address name="window_y" value="0x8d65c74" />
<Address name="window_z" value="0x8d65c78" />
</Group>
<Group name="Maps">
<Address name="world_size_x" value="0x94391f0" />
<Address name="world_size_y" value="0x94391f2" />
<Group name="features" valid="true">
<Group name="global">
<Address name="vector" value="0x94397cc" />
<!--
<Offset name="funcptr" value="0x94" />
<Offset name="material" value="0x28" />
<Offset name="submaterial" value="0x2c" />
-->
</Group>
<Group name="local">
<Address name="start_ptr" value="0x9439844" />
<!--
<Offset name="material" value="0x24" />
<Offset name="submaterial" value="0x28" />
-->
</Group>
</Group>
<Group name="geology" valid="true">
<Address name="geoblock_vector" value="0x94397e4" />
<Address name="ptr2_region_array" value="0x9439808" />
</Group>
</Group>
<Group name="GUI">
<Address name="pause_state" value="0x93dddf0" />
</Group>
<Group name="Materials">
<Address name="creature_type_vector" value="0x943a074" />
<Address name="inorganics" value="0x9439fc0" />
<Address name="organics_all" value="0x9439fd8" />
<Address name="organics_plants" value="0x9439fe4" />
<Address name="organics_trees" value="0x9439ffc" />
-------------------
!!LANGUAGE TABLES!!
-------------------
translation vector: 0x943a21c
lang vector: 0x943a204
word table offset: 0x1c
-------------
!!MATERIALS!!
-------------
inorganics:
0x9439fc0
organics:
0x9439fd8
organics 31.19:
trees:
0x9439ffc
plants:
0x9439fe4
color descriptors:
0x943e368
Amber color:0xa380190
all descriptors:
0x943e380
toad-first creature types:
0x943a074
all creature types:
0x943a068
0x943a074
Toad: 0xa441f10
Toad: rawname = 0x0
Toad: character (not reliable) = 0x20
Toad: caste vector = 0x60
Toad: extract? vector = 0x1f74
Toad: colors = 0x38
</Group>
</Offsets>
</Version>
</DFHack>

@ -29,6 +29,10 @@ include_directories (${CMAKE_SOURCE_DIR}/library/private/)
SET(PROJECT_HDRS_INTERNAL
private/ContextShared.h
private/Internal.h
private/SHMProcess.h
private/LinuxProcess.h
private/ProcessFactory.h
private/MicrosoftSTL.h
)
SET(PROJECT_HDRS
@ -86,8 +90,11 @@ VersionInfo.cpp
VersionInfoFactory.cpp
DFContextManager.cpp
DFContext.cpp
DFTileTypes.cpp
DFProcessEnumerator.cpp
ContextShared.cpp
DFProcess-SHM.cpp
MicrosoftSTL.cpp
depends/md5/md5.cpp
depends/md5/md5wrapper.cpp
@ -137,6 +144,7 @@ include/dfhack/DFstdint_win.h
SET(PROJECT_SRCS_LINUX
DFProcess-linux.cpp
DFProcess-linux-base.cpp
DFProcess-linux-SHM.cpp
DFProcess-linux-wine.cpp
modules/WindowIO-linux.cpp
@ -190,7 +198,12 @@ IF(UNIX)
SET(PROJECT_LIBS ${X11_LIBRARY} rt ) #dfhack-md5 dfhack-tixml
ELSE(UNIX)
SET(PROJECT_LIBS psapi)
IF(MSVC)
SET(PROJECT_LIBS psapi ${CMAKE_SOURCE_DIR}/library/depends/ntdll/ntdll.lib)
ELSE(MSVC)
SET(PROJECT_LIBS psapi ntdll)
ENDIF(MSVC)
ENDIF(UNIX)
ADD_LIBRARY(dfhack SHARED ${PROJECT_SRCS})

@ -31,7 +31,7 @@ DFContextShared::DFContextShared()
DFContextShared::~DFContextShared()
{
// invalidate all modules
for(int i = 0 ; i < allModules.size(); i++)
for(unsigned int i = 0 ; i < allModules.size(); i++)
{
delete allModules[i];
}

@ -93,68 +93,12 @@ bool Context::Detach()
}
d->shm_start = 0;
// invalidate all modules
for(int i = 0 ; i < d->allModules.size(); i++)
for(unsigned int i = 0 ; i < d->allModules.size(); i++)
{
delete d->allModules[i];
}
d->allModules.clear();
memset(&(d->s_mods), 0, sizeof(d->s_mods));
/*
if(d->creatures)
{
delete d->creatures;
d->creatures = 0;
}
if(d->maps)
{
delete d->maps;
d->maps = 0;
}
if(d->gui)
{
delete d->gui;
d->gui = 0;
}
if(d->world)
{
delete d->world;
d->world = 0;
}
if(d->position)
{
delete d->position;
d->position = 0;
}
if(d->materials)
{
delete d->materials;
d->materials = 0;
}
if(d->items)
{
delete d->items;
d->items = 0;
}
if(d->translation)
{
delete d->translation;
d->translation = 0;
}
if(d->vegetation)
{
delete d->vegetation;
d->vegetation = 0;
}
if(d->constructions)
{
delete d->constructions;
d->constructions = 0;
}
if(d->translation)
{
delete d->translation;
d->translation = 0;
}*/
return true;
}
@ -174,7 +118,7 @@ bool Context::AsyncSuspend()
bool Context::Resume()
{
for(int i = 0 ; i < d->allModules.size(); i++)
for(unsigned int i = 0 ; i < d->allModules.size(); i++)
{
d->allModules[i]->OnResume();
}
@ -236,386 +180,3 @@ MODULE_GETTER(Translation);
MODULE_GETTER(Vegetation);
MODULE_GETTER(Buildings);
MODULE_GETTER(Constructions);
/*
Creatures * Context::getCreatures()
{
if(!d->creatures)
d->creatures = new Creatures(d);
return d->creatures;
}
*/
/*
Maps * Context::getMaps()
{
if(!d->maps)
d->maps = new Maps(d);
return d->maps;
}
Gui * Context::getGui()
{
if(!d->gui)
d->gui = new Gui(d);
return d->gui;
}
WindowIO * Context::getWindow()
{
if(!d->windowio)
d->windowio = new WindowIO(d);
return d->windowio;
}
World * Context::getWorld()
{
if(!d->world)
d->world = new World(d);
return d->world;
}
Position * Context::getPosition()
{
if(!d->position)
d->position = new Position(d);
return d->position;
}
Materials * Context::getMaterials()
{
if(!d->materials)
d->materials = new Materials(d);
return d->materials;
}
Items * Context::getItems()
{
if(!d->items)
d->items = new Items(d);
return d->items;
}
Translation * Context::getTranslation()
{
if(!d->translation)
d->translation = new Translation(d);
return d->translation;
}
Vegetation * Context::getVegetation()
{
if(!d->vegetation)
d->vegetation = new Vegetation(d);
return d->vegetation;
}
Buildings * Context::getBuildings()
{
if(!d->buildings)
d->buildings = new Buildings(d);
return d->buildings;
}
Constructions * Context::getConstructions()
{
if(!d->constructions)
d->constructions = new Constructions(d);
return d->constructions;
}
*/
/*
// returns number of buildings, expects v_buildingtypes that will later map t_building.type to its name
bool API::InitReadEffects ( uint32_t & numeffects )
{
if(d->effectsInited)
FinishReadEffects();
int effects = 0;
try
{
effects = d->offset_descriptor->getAddress ("effects_vector");
}
catch(Error::MissingMemoryDefinition)
{
return false;
}
d->effectsInited = true;
d->p_effect = new DfVector (d->p, effects);
numeffects = d->p_effect->getSize();
return true;
}
bool API::ReadEffect(const uint32_t index, t_effect_df40d & effect)
{
if(!d->effectsInited)
return false;
if(index >= d->p_effect->getSize())
return false;
// read pointer from vector at position
uint32_t temp = d->p_effect->at (index);
//read effect from memory
d->p->read (temp, sizeof (t_effect_df40d), (uint8_t *) &effect);
return true;
}
// use with care!
bool API::WriteEffect(const uint32_t index, const t_effect_df40d & effect)
{
if(!d->effectsInited)
return false;
if(index >= d->p_effect->getSize())
return false;
// read pointer from vector at position
uint32_t temp = d->p_effect->at (index);
// write effect to memory
d->p->write(temp,sizeof(t_effect_df40d), (uint8_t *) &effect);
return true;
}
void API::FinishReadEffects()
{
if(d->p_effect)
{
delete d->p_effect;
d->p_effect = NULL;
}
d->effectsInited = false;
}
*/
/*
bool API::InitReadNotes( uint32_t &numnotes )
{
try
{
memory_info * minfo = d->offset_descriptor;
int notes = minfo->getAddress ("notes");
d->note_foreground_offset = minfo->getOffset ("note_foreground");
d->note_background_offset = minfo->getOffset ("note_background");
d->note_name_offset = minfo->getOffset ("note_name");
d->note_xyz_offset = minfo->getOffset ("note_xyz");
d->p_notes = new DfVector (d->p, notes);
d->notesInited = true;
numnotes = d->p_notes->getSize();
return true;
}
catch (Error::MissingMemoryDefinition&)
{
d->notesInited = false;
numnotes = 0;
throw;
}
}
bool API::ReadNote (const int32_t index, t_note & note)
{
if(!d->notesInited) return false;
// read pointer from vector at position
uint32_t temp = d->p_notes->at (index);
note.symbol = d->p->readByte(temp);
note.foreground = d->p->readWord(temp + d->note_foreground_offset);
note.background = d->p->readWord(temp + d->note_background_offset);
d->p->readSTLString (temp + d->note_name_offset, note.name, 128);
d->p->read (temp + d->note_xyz_offset, 3*sizeof (uint16_t), (uint8_t *) &note.x);
return true;
}
bool API::InitReadSettlements( uint32_t & numsettlements )
{
if(!d->InitReadNames()) return false;
try
{
memory_info * minfo = d->offset_descriptor;
int allSettlements = minfo->getAddress ("settlements");
int currentSettlement = minfo->getAddress("settlement_current");
d->settlement_name_offset = minfo->getOffset ("settlement_name");
d->settlement_world_xy_offset = minfo->getOffset ("settlement_world_xy");
d->settlement_local_xy_offset = minfo->getOffset ("settlement_local_xy");
d->p_settlements = new DfVector (d->p, allSettlements);
d->p_current_settlement = new DfVector(d->p, currentSettlement);
d->settlementsInited = true;
numsettlements = d->p_settlements->getSize();
return true;
}
catch (Error::MissingMemoryDefinition&)
{
d->settlementsInited = false;
numsettlements = 0;
throw;
}
}
bool API::ReadSettlement(const int32_t index, t_settlement & settlement)
{
if(!d->settlementsInited) return false;
if(!d->p_settlements->getSize()) return false;
// read pointer from vector at position
uint32_t temp = d->p_settlements->at (index);
settlement.origin = temp;
d->readName(settlement.name, temp + d->settlement_name_offset);
d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x);
d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1);
return true;
}
bool API::ReadCurrentSettlement(t_settlement & settlement)
{
if(!d->settlementsInited) return false;
if(!d->p_current_settlement->getSize()) return false;
uint32_t temp = d->p_current_settlement->at(0);
settlement.origin = temp;
d->readName(settlement.name, temp + d->settlement_name_offset);
d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x);
d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1);
return true;
}
void API::FinishReadSettlements()
{
if(d->p_settlements)
{
delete d->p_settlements;
d->p_settlements = NULL;
}
if(d->p_current_settlement)
{
delete d->p_current_settlement;
d->p_current_settlement = NULL;
}
d->settlementsInited = false;
}
bool API::getItemIndexesInBox(vector<uint32_t> &indexes,
const uint16_t x1, const uint16_t y1, const uint16_t z1,
const uint16_t x2, const uint16_t y2, const uint16_t z2)
{
if(!d->itemsInited) return false;
indexes.clear();
uint32_t size = d->p_itm->getSize();
struct temp2{
uint16_t coords[3];
uint32_t flags;
};
temp2 temp2;
for(uint32_t i =0;i<size;i++){
uint32_t temp = d->p_itm->at(i);
d->p->read(temp+sizeof(uint32_t),5 * sizeof(uint16_t), (uint8_t *) &temp2);
if(temp2.flags & (1 << 0)){
if (temp2.coords[0] >= x1 && temp2.coords[0] < x2)
{
if (temp2.coords[1] >= y1 && temp2.coords[1] < y2)
{
if (temp2.coords[2] >= z1 && temp2.coords[2] < z2)
{
indexes.push_back(i);
}
}
}
}
}
return true;
}
*/
/*
void API::FinishReadNotes()
{
if(d->p_notes)
{
delete d->p_notes;
d->p_notes = 0;
}
d->notesInited = false;
}
*/
/*
bool API::InitReadItems(uint32_t & numitems)
{
try
{
int items = d->offset_descriptor->getAddress ("items");
d->item_material_offset = d->offset_descriptor->getOffset ("item_materials");
d->p_itm = new DfVector (d->p, items);
d->itemsInited = true;
numitems = d->p_itm->getSize();
return true;
}
catch (Error::MissingMemoryDefinition&)
{
d->itemsInited = false;
numitems = 0;
throw;
}
}
bool API::ReadItem (const uint32_t index, t_item & item)
{
if (!d->itemsInited) return false;
t_item_df40d item_40d;
// read pointer from vector at position
uint32_t temp = d->p_itm->at (index);
//read building from memory
d->p->read (temp, sizeof (t_item_df40d), (uint8_t *) &item_40d);
// transform
int32_t type = -1;
d->offset_descriptor->resolveObjectToClassID (temp, type);
item.origin = temp;
item.vtable = item_40d.vtable;
item.x = item_40d.x;
item.y = item_40d.y;
item.z = item_40d.z;
item.type = type;
item.ID = item_40d.ID;
item.flags.whole = item_40d.flags;
//TODO certain item types (creature based, threads, seeds, bags do not have the first matType byte, instead they have the material index only located at 0x68
d->p->read (temp + d->item_material_offset, sizeof (t_matglossPair), (uint8_t *) &item.material);
//for(int i = 0; i < 0xCC; i++){ // used for item research
// uint8_t byte = MreadByte(temp+i);
// item.bytes.push_back(byte);
//}
return true;
}
void API::FinishReadItems()
{
if(d->p_itm)
{
delete d->p_itm;
d->p_itm = NULL;
}
d->itemsInited = false;
}
*/
/*
bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes)
{
memory_info * minfo = d->offset_descriptor;
int matgloss_address = minfo->getAddress("matgloss");
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->p, matgloss_address + i*matgloss_skip);
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->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);
}
itemTypes.push_back(typesForVec);
}
return true;
}
*/

@ -69,7 +69,7 @@ BadContexts::~BadContexts()
bool BadContexts::Contains(Process* p)
{
for(int i = 0; i < d->bad.size(); i++)
for(unsigned int i = 0; i < d->bad.size(); i++)
{
if((d->bad[i])->getProcess() == p)
return true;
@ -79,7 +79,7 @@ bool BadContexts::Contains(Process* p)
bool BadContexts::Contains(Context* c)
{
for(int i = 0; i < d->bad.size(); i++)
for(unsigned int i = 0; i < d->bad.size(); i++)
{
if(d->bad[i] == c)
return true;
@ -94,7 +94,7 @@ uint32_t BadContexts::size()
void BadContexts::clear()
{
for(int i = 0; i < d->bad.size(); i++)
for(unsigned int i = 0; i < d->bad.size(); i++)
{
// delete both Process and Context!
// process has to be deleted after context, because Context does some
@ -227,7 +227,7 @@ Context * ContextManager::getSingleContext()
{
Refresh();
}
for(int i = 0; i < d->contexts.size();i++)
for(unsigned int i = 0; i < d->contexts.size();i++)
{
if(d->contexts[i]->isValid())
{
@ -239,8 +239,8 @@ Context * ContextManager::getSingleContext()
void ContextManager::purge(void)
{
for(int i = 0; i < d->contexts.size();i++)
for(unsigned int i = 0; i < d->contexts.size();i++)
delete d->contexts[i];
d->contexts.clear();
d->pEnum->purge();
}
}

@ -0,0 +1,485 @@
/*
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 "Internal.h"
#include "SHMProcess.h"
#include "ProcessFactory.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
#include "shms.h"
#include "mod-core.h"
using namespace DFHack;
Process* DFHack::createSHMProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
{
return new SHMProcess(pid, known_versions);
}
SHMProcess::SHMProcess(uint32_t PID, vector <VersionInfo *> & known_versions)
: d(new Private(this))
{
d->process_ID = PID;
// attach the SHM
if(!attach())
{
return;
}
// Test bridge version, get PID, sync Yield
bool bridgeOK;
if(!d->Aux_Core_Attach(bridgeOK,d->process_ID))
{
detach();
throw Error::SHMAttachFailure();
}
else if(!bridgeOK)
{
detach();
throw Error::SHMVersionMismatch();
}
// try to identify the DF version (md5 the binary, compare with known versions)
d->validate(known_versions);
// at this point, DF is attached and suspended, make it run
detach();
}
SHMProcess::~SHMProcess()
{
if(d->attached)
{
detach();
}
// destroy data model. this is assigned by processmanager
if(d->memdescriptor)
delete d->memdescriptor;
delete d;
}
VersionInfo * SHMProcess::getDescriptor()
{
return d->memdescriptor;
}
int SHMProcess::getPID()
{
return d->process_ID;
}
bool SHMProcess::isSuspended()
{
return d->locked;
}
bool SHMProcess::isAttached()
{
return d->attached;
}
bool SHMProcess::isIdentified()
{
return d->identified;
}
bool SHMProcess::suspend()
{
if(!d->attached)
{
return false;
}
if(d->locked)
{
return true;
}
//cerr << "suspend" << endl;// FIXME: throw
// FIXME: this should be controlled on the server side
// FIXME: IF server got CORE_RUN in this frame, interpret CORE_SUSPEND as CORE_STEP
// did we just resume a moment ago?
if(D_SHMCMD == CORE_RUN)
{
//fprintf(stderr,"%d invokes step\n",attachmentIdx);
// wait for the next window
/*
if(!d->SetAndWait(CORE_STEP))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))");
}
*/
D_SHMCMD = CORE_STEP;
}
else
{
//fprintf(stderr,"%d invokes suspend\n",attachmentIdx);
// lock now
/*
if(!d->SetAndWait(CORE_SUSPEND))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))");
}
*/
D_SHMCMD = CORE_SUSPEND;
}
//fprintf(stderr,"waiting for lock\n");
// we wait for the server to give up our suspend lock (held by default)
if(acquireSuspendLock())
{
d->locked = true;
return true;
}
return false;
}
// FIXME: needs a good think-through
bool SHMProcess::asyncSuspend()
{
if(!d->attached)
{
return false;
}
if(d->locked)
{
return true;
}
//cerr << "async suspend" << endl;// FIXME: throw
uint32_t cmd = D_SHMCMD;
if(cmd == CORE_SUSPENDED)
{
// we have to hold the lock to be really suspended
if(acquireSuspendLock())
{
d->locked = true;
return true;
}
return false;
}
else
{
// did we just resume a moment ago?
if(cmd == CORE_STEP)
{
return false;
}
else if(cmd == CORE_RUN)
{
D_SHMCMD = CORE_STEP;
}
else
{
D_SHMCMD = CORE_SUSPEND;
}
return false;
}
}
bool SHMProcess::forceresume()
{
return resume();
}
// FIXME: wait for the server to advance a step!
bool SHMProcess::resume()
{
if(!d->attached)
return false;
if(!d->locked)
return true;
//cerr << "resume" << endl;// FIXME: throw
// unlock the suspend lock
if(releaseSuspendLock())
{
d->locked = false;
if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds!
{
return true;
}
throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))");
}
throw Error::SHMLockingError("if(releaseSuspendLock())");
return false;
}
// get module index by name and version. bool 0 = error
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
{
if(!d->locked) throw Error::MemoryAccessDenied();
modulelookup * payload = D_SHMDATA(modulelookup);
payload->version = version;
strncpy(payload->name,name,255);
payload->name[255] = 0;
if(!SetAndWait(CORE_ACQUIRE_MODULE))
{
return false; // FIXME: throw a fatal exception instead
}
if(D_SHMHDR->error)
{
return false;
}
//fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value);
OUTPUT = D_SHMHDR->value;
return true;
}
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
{
if(!locked) throw Error::MemoryAccessDenied();
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
if(!SetAndWait(CORE_ATTACH)) return false;
/*
cerr <<"CORE_VERSION" << CORE_VERSION << endl;
cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl;
*/
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield;
#ifdef DEBUG
if(useYield) cerr << "Using Yield!" << endl;
#endif
return true;
}
void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal read under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = src_address;
D_SHMHDR->length = size;
full_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void),size);
}
// a big read, we pull data over the shm in iterations
else
{
// first read equals the size of the SHM window
uint32_t to_read = SHM_BODY;
while (size)
{
// read to_read bytes from src_cursor
D_SHMHDR->address = src_address;
D_SHMHDR->length = to_read;
full_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void) ,to_read);
// decrease size by bytes read
size -= to_read;
// move the cursors
src_address += to_read;
target_buffer += to_read;
// check how much to write in the next iteration
to_read = min(size, (uint32_t) SHM_BODY);
}
}
}
void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_BYTE);
val = D_SHMHDR->value;
}
void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_WORD);
val = D_SHMHDR->value;
}
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
val = D_SHMHDR->value;
}
void SHMProcess::readQuad (const uint32_t offset, uint64_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_QUAD);
val = D_SHMHDR->Qvalue;
}
void SHMProcess::readFloat (const uint32_t offset, float &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
val = reinterpret_cast<float&> (D_SHMHDR->value);
}
/*
* WRITING
*/
void SHMProcess::writeQuad (uint32_t offset, uint64_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->Qvalue = data;
full_barrier
d->SetAndWait(CORE_WRITE_QUAD);
}
void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_DWORD);
}
// using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_WORD);
}
void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_BYTE);
}
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal write under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = dst_address;
D_SHMHDR->length = size;
memcpy(D_SHMDATA(void),source_buffer, size);
full_barrier
d->SetAndWait(CORE_WRITE);
}
// a big write, we push this over the shm in iterations
else
{
// first write equals the size of the SHM window
uint32_t to_write = SHM_BODY;
while (size)
{
// write to_write bytes to dst_cursor
D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write;
memcpy(D_SHMDATA(void),source_buffer, to_write);
full_barrier
d->SetAndWait(CORE_WRITE);
// decrease size by bytes written
size -= to_write;
// move the cursors
source_buffer += to_write;
dst_address += to_write;
// check how much to write in the next iteration
to_write = min(size, (uint32_t) SHM_BODY);
}
}
}
// FIXME: butt-fugly
const std::string SHMProcess::readCString (uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = Process::readByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r && counter < 255);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}
const std::string SHMProcess::readSTLString(uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
return(string( D_SHMDATA(char) ));
}
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value;
size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,D_SHMDATA(char),fit);
buffer[fit] = 0;
return fit;
}
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = address;
strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
d->SetAndWait(CORE_WRITE_STL_STRING);
}

@ -22,7 +22,7 @@ must not be misrepresented as being the original software.
distribution.
*/
#include "Internal.h"
#include "dfhack/DFProcess.h"
#include "SHMProcess.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
@ -39,76 +39,37 @@ distribution.
using namespace DFHack;
// a full memory barrier! better be safe than sorry.
#define gcc_barrier asm volatile("" ::: "memory"); __sync_synchronize();
class SHMProcess::Private
SHMProcess::Private::Private(SHMProcess * self_)
{
public:
Private(Process * self_)
{
memdescriptor = NULL;
process_ID = 0;
shm_addr = 0;
//shm_addr_with_cl_idx = 0;
shm_ID = -1;
attached = false;
identified = false;
useYield = false;
server_lock = -1;
client_lock = -1;
suspend_lock = -1;
attachmentIdx = 0;
locked = false;
self = self_;
};
~Private(){};
VersionInfo * memdescriptor;
Process * self;
pid_t process_ID;
char *shm_addr;
int shm_ID;
Process* q;
int server_lock;
int client_lock;
int suspend_lock;
int attachmentIdx;
bool attached;
bool locked;
bool identified;
bool useYield;
bool validate(std::vector< VersionInfo* >& known_versions);
bool Aux_Core_Attach(bool & versionOK, pid_t & PID);
//bool waitWhile (uint32_t state);
bool SetAndWait (uint32_t state);
bool GetLocks();
bool AreLocksOk();
void FreeLocks();
};
#define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx]
#define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx]
#define SHMHDR ((shm_core_hdr *)shm_addr)
#define D_SHMHDR ((shm_core_hdr *)(d->shm_addr))
#define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER))
#define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER))
memdescriptor = NULL;
process_ID = 0;
shm_ID = -1;
attached = false;
identified = false;
useYield = false;
server_lock = -1;
client_lock = -1;
suspend_lock = -1;
locked = false;
self = self_;
}
bool SHMProcess::Private::SetAndWait (uint32_t state)
{
uint32_t cnt = 0;
if(!attached) return false;
SHMCMD = state;
while (SHMCMD == state)
{
// check if the other process is still there
// yield the CPU, only on single-core CPUs
if(useYield)
{
SCHED_YIELD
}
if(cnt == 10000)
{
if(!AreLocksOk())
if(!AreLocksOk())// DF not there anymore?
{
//detach the shared memory
shmdt(shm_addr);
@ -122,10 +83,6 @@ bool SHMProcess::Private::SetAndWait (uint32_t state)
cnt = 0;
}
}
if(useYield)
{
SCHED_YIELD
}
cnt++;
}
// server returned a generic error
@ -155,21 +112,6 @@ uint32_t OS_getAffinity()
return affinity;
}
// test if we have client and server locks and the server is present
bool SHMProcess::Private::AreLocksOk()
{
// both locks are inited (we hold our lock)
if(client_lock != -1 && server_lock != -1)
{
if(lockf(server_lock,F_TEST,0) == -1) // and server holds its lock
{
return true; // OK, locks are good
}
}
// locks are bad
return false;
}
void SHMProcess::Private::FreeLocks()
{
attachmentIdx = -1;
@ -258,50 +200,21 @@ bool SHMProcess::Private::GetLocks()
return false;
}
SHMProcess::SHMProcess(uint32_t PID, vector< VersionInfo* >& known_versions)
: d(new Private(this))
// test if we have client and server locks and the server is present
bool SHMProcess::Private::AreLocksOk()
{
d->process_ID = PID;
d->memdescriptor = 0;
if(!attach())
{
// couldn't attach to process
return;
}
/*
* Test bridge version, get PID, sync Yield
*/
bool bridgeOK;
if(!d->Aux_Core_Attach(bridgeOK,d->process_ID))
{
detach();
throw Error::SHMAttachFailure();
}
if(!bridgeOK)
// both locks are inited (we hold our lock)
if(client_lock != -1 && server_lock != -1)
{
detach();
throw Error::SHMVersionMismatch();
if(lockf(server_lock,F_TEST,0) == -1) // and server holds its lock
{
return true; // OK, locks are good
}
}
// try to identify the DF version (md5 the binary, compare with known versions)
d->validate(known_versions);
// detach
detach();
}
bool SHMProcess::isSuspended()
{
return d->locked;
}
bool SHMProcess::isAttached()
{
return d->attached;
// locks are bad
return false;
}
bool SHMProcess::isIdentified()
{
return d->identified;
}
bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
{
@ -333,13 +246,13 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
{
VersionInfo *m = new VersionInfo(**it);
memdescriptor = m;
m->setParentProcess(dynamic_cast<Process *>( self ));
m->setParentProcess(self);
identified = true;
// cerr << "identified " << m->getVersion() << endl;
return true;
}
}
catch (Error::MissingMemoryDefinition&)
catch (Error::AllMemdef&)
{
continue;
}
@ -347,27 +260,6 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
return false;
}
SHMProcess::~SHMProcess()
{
if(d->attached)
{
detach();
}
if(d->memdescriptor)
delete d->memdescriptor;
delete d;
}
VersionInfo * SHMProcess::getDescriptor()
{
return d->memdescriptor;
}
int SHMProcess::getPID()
{
return d->process_ID;
}
// there is only one we care about.
bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
{
@ -403,123 +295,19 @@ void SHMProcess::getMemRanges( vector<t_memrange> & ranges )
temp.read = permissions[0] == 'r';
temp.write = permissions[1] == 'w';
temp.execute = permissions[2] == 'x';
temp.valid = true;
ranges.push_back(temp);
}
}
bool SHMProcess::suspend()
bool SHMProcess::acquireSuspendLock()
{
if(!d->attached)
{
return false;
}
if(d->locked)
{
return true;
}
// FIXME: this should be controlled on the server side
// FIXME: IF server got CORE_RUN in this frame, interpret CORE_SUSPEND as CORE_STEP
// did we just resume a moment ago?
if(D_SHMCMD == CORE_RUN)
{
//fprintf(stderr,"%d invokes step\n",d->attachmentIdx);
/*
// wait for the next window
if(!d->SetAndWait(CORE_STEP))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))");
}
*/
D_SHMCMD = CORE_STEP;
}
else
{
//fprintf(stderr,"%d invokes suspend\n",d->attachmentIdx);
// lock now
/*
if(!d->SetAndWait(CORE_SUSPEND))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))");
}
*/
D_SHMCMD = CORE_SUSPEND;
}
//fprintf(stderr,"waiting for lock\n");
// we wait for the server to give up our suspend lock (held by default)
if(lockf(d->suspend_lock,F_LOCK,0) == 0)
{
d->locked = true;
return true;
}
return false;
return (lockf(d->suspend_lock,F_LOCK,0) == 0);
}
// FIXME: needs a good think-through
bool SHMProcess::asyncSuspend()
bool SHMProcess::releaseSuspendLock()
{
if(!d->attached)
{
return false;
}
if(d->locked)
{
return true;
}
uint32_t cmd = D_SHMCMD;
if(cmd == CORE_SUSPENDED)
{
// we have to hold the lock to be really suspended
if(lockf(d->suspend_lock,F_LOCK,0) == 0)
{
d->locked = true;
return true;
}
return false;
}
else
{
// did we just resume a moment ago?
if(cmd == CORE_STEP)
{
return false;
}
else if(cmd == CORE_RUN)
{
D_SHMCMD = CORE_STEP;
}
else
{
D_SHMCMD = CORE_SUSPEND;
}
return false;
}
}
bool SHMProcess::forceresume()
{
return resume();
}
// FIXME: wait for the server to advance a step!
bool SHMProcess::resume()
{
if(!d->attached)
return false;
if(!d->locked)
return true;
// unlock the suspend lock
if(lockf(d->suspend_lock,F_ULOCK,0) == 0)
{
d->locked = false;
if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds!
{
return true;
}
throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))");
}
throw Error::SHMLockingError("if(lockf(d->suspend_lock,F_ULOCK,0) == 0)");
return false;
return (lockf(d->suspend_lock,F_ULOCK,0) == 0);
}
@ -531,6 +319,7 @@ bool SHMProcess::attach()
return suspend();
return true;
}
//cerr << "attach" << endl;// FIXME: throw
if(!d->GetLocks())
{
//cerr << "server is full or not really there!" << endl;
@ -589,334 +378,34 @@ bool SHMProcess::detach()
return false;
}
void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal read under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = src_address;
D_SHMHDR->length = size;
gcc_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void),size);
}
// a big read, we pull data over the shm in iterations
else
{
// first read equals the size of the SHM window
uint32_t to_read = SHM_BODY;
while (size)
{
// read to_read bytes from src_cursor
D_SHMHDR->address = src_address;
D_SHMHDR->length = to_read;
gcc_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void) ,to_read);
// decrease size by bytes read
size -= to_read;
// move the cursors
src_address += to_read;
target_buffer += to_read;
// check how much to write in the next iteration
to_read = min(size, (uint32_t) SHM_BODY);
}
}
}
uint8_t SHMProcess::readByte (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_BYTE);
return D_SHMHDR->value;
}
void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_BYTE);
val = D_SHMHDR->value;
}
uint16_t SHMProcess::readWord (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_WORD);
return D_SHMHDR->value;
}
void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_WORD);
val = D_SHMHDR->value;
}
uint32_t SHMProcess::readDWord (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_DWORD);
return D_SHMHDR->value;
}
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_DWORD);
val = D_SHMHDR->value;
}
uint64_t SHMProcess::readQuad (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_QUAD);
return D_SHMHDR->Qvalue;
}
void SHMProcess::readQuad (const uint32_t offset, uint64_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_QUAD);
val = D_SHMHDR->Qvalue;
}
float SHMProcess::readFloat (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_DWORD);
return reinterpret_cast<float&> (D_SHMHDR->value);
}
void SHMProcess::readFloat (const uint32_t offset, float &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
gcc_barrier
d->SetAndWait(CORE_READ_DWORD);
val = reinterpret_cast<float&> (D_SHMHDR->value);
}
/*
* WRITING
*/
void SHMProcess::writeQuad (const uint32_t offset, const uint64_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->Qvalue = data;
gcc_barrier
d->SetAndWait(CORE_WRITE_QUAD);
}
void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
d->SetAndWait(CORE_WRITE_DWORD);
}
// using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
d->SetAndWait(CORE_WRITE_WORD);
}
void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
gcc_barrier
d->SetAndWait(CORE_WRITE_BYTE);
}
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal write under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = dst_address;
D_SHMHDR->length = size;
memcpy(D_SHMDATA(void),source_buffer, size);
gcc_barrier
d->SetAndWait(CORE_WRITE);
}
// a big write, we push this over the shm in iterations
else
{
// first write equals the size of the SHM window
uint32_t to_write = SHM_BODY;
while (size)
{
// write to_write bytes to dst_cursor
D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write;
memcpy(D_SHMDATA(void),source_buffer, to_write);
gcc_barrier
d->SetAndWait(CORE_WRITE);
// decrease size by bytes written
size -= to_write;
// move the cursors
source_buffer += to_write;
dst_address += to_write;
// check how much to write in the next iteration
to_write = min(size, (uint32_t) SHM_BODY);
}
}
}
// FIXME: butt-fugly
const std::string SHMProcess::readCString (uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
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;
}
const std::string SHMProcess::readSTLString(uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
return(string( D_SHMDATA(char) ));
}
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value;
size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,D_SHMDATA(char),fit);
buffer[fit] = 0;
return fit;
}
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = address;
strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
d->SetAndWait(CORE_WRITE_STL_STRING);
}
string SHMProcess::readClassName (uint32_t vptr)
{
if(!d->locked) throw Error::MemoryAccessDenied();
int typeinfo = readDWord(vptr - 0x4);
int typestring = readDWord(typeinfo + 0x4);
int typeinfo = Process::readDWord(vptr - 0x4);
int typestring = Process::readDWord(typeinfo + 0x4);
string raw = readCString(typestring);
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
size_t end = raw.length();
return raw.substr(start,end-start);
}
// get module index by name and version. bool 0 = error
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
string SHMProcess::getPath()
{
if(!d->locked) throw Error::MemoryAccessDenied();
modulelookup * payload = D_SHMDATA(modulelookup);
payload->version = version;
strncpy(payload->name,name,255);
payload->name[255] = 0;
char cwd_name[256];
char target_name[1024];
int target_result;
if(!SetAndWait(CORE_ACQUIRE_MODULE))
{
return false; // FIXME: throw a fatal exception instead
}
if(D_SHMHDR->error)
{
return false;
}
//fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value);
OUTPUT = D_SHMHDR->value;
return true;
sprintf(cwd_name,"/proc/%d/cwd", getPID());
// resolve /proc/PID/exe link
target_result = readlink(cwd_name, target_name, sizeof(target_name));
target_name[target_result] = '\0';
return(string(target_name));
}
char * SHMProcess::getSHMStart (void)
{
if(!d->locked) return 0; //THROW HERE!
return /*d->shm_addr_with_cl_idx*/ d->shm_addr;
}
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
{
if(!locked) throw Error::MemoryAccessDenied();
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
if(!SetAndWait(CORE_ATTACH)) return false;
/*
cerr <<"CORE_VERSION" << CORE_VERSION << endl;
cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl;
*/
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield;
#ifdef DEBUG
if(useYield) cerr << "Using Yield!" << endl;
#endif
return true;
return d->shm_addr;
}

@ -0,0 +1,432 @@
/*
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 "Internal.h"
#include "LinuxProcess.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
#include <errno.h>
#include <sys/ptrace.h>
using namespace DFHack;
LinuxProcessBase::LinuxProcessBase(uint32_t pid)
: my_pid(pid)
{
my_descriptor = NULL;
attached = false;
suspended = false;
memFileHandle = 0;
}
bool LinuxProcessBase::isSuspended()
{
return suspended;
}
bool LinuxProcessBase::isAttached()
{
return attached;
}
bool LinuxProcessBase::isIdentified()
{
return identified;
}
LinuxProcessBase::~LinuxProcessBase()
{
if(attached)
{
detach();
}
// destroy our copy of the memory descriptor
if(my_descriptor)
delete my_descriptor;
}
VersionInfo * LinuxProcessBase::getDescriptor()
{
return my_descriptor;
}
int LinuxProcessBase::getPID()
{
return my_pid;
}
//FIXME: implement
bool LinuxProcessBase::getThreadIDs(vector<uint32_t> & threads )
{
return false;
}
//FIXME: cross-reference with ELF segment entries?
void LinuxProcessBase::getMemRanges( vector<t_memrange> & ranges )
{
char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0
sprintf(buffer, "/proc/%lu/maps", 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';
temp.valid = true;
ranges.push_back(temp);
}
}
bool LinuxProcessBase::asyncSuspend()
{
return suspend();
}
bool LinuxProcessBase::suspend()
{
int status;
if(!attached)
return false;
if(suspended)
return true;
if (kill(my_pid, SIGSTOP) == -1)
{
// no, we got an error
perror("kill SIGSTOP error");
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(my_pid, &status, 0);
if (w == -1)
{
// child died
perror("DF exited during suspend call");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
suspended = true;
return true;
}
bool LinuxProcessBase::forceresume()
{
return resume();
}
bool LinuxProcessBase::resume()
{
if(!attached)
return false;
if(!suspended)
return true;
if (ptrace(PTRACE_CONT, my_pid, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace resume error");
return false;
}
suspended = false;
return true;
}
bool LinuxProcessBase::attach()
{
int status;
if(attached)
{
if(!suspended)
return suspend();
return true;
}
// can we attach?
if (ptrace(PTRACE_ATTACH , my_pid, NULL, NULL) == -1)
{
// no, we got an error
perror("ptrace attach error");
cerr << "attach failed on pid " << my_pid << endl;
return false;
}
while(true)
{
// we wait on the pid
pid_t w = waitpid(my_pid, &status, 0);
if (w == -1)
{
// child died
perror("wait inside attach()");
return false;
}
// stopped -> let's continue
if (WIFSTOPPED(status))
{
break;
}
}
suspended = true;
int proc_pid_mem = open(memFile.c_str(),O_RDONLY);
if(proc_pid_mem == -1)
{
ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
cerr << memFile << endl;
cerr << "couldn't open /proc/" << my_pid << "/mem" << endl;
perror("open(memFile.c_str(),O_RDONLY)");
return false;
}
else
{
attached = true;
memFileHandle = proc_pid_mem;
return true; // we are attached
}
}
bool LinuxProcessBase::detach()
{
if(!attached) return true;
if(!suspended) suspend();
int result = 0;
// close /proc/PID/mem
result = close(memFileHandle);
if(result == -1)
{
cerr << "couldn't close /proc/"<< my_pid <<"/mem" << endl;
perror("mem file close");
return false;
}
else
{
// detach
result = ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
if(result == -1)
{
cerr << "couldn't detach from process pid" << my_pid << endl;
perror("ptrace detach");
return false;
}
else
{
attached = false;
return true;
}
}
}
void LinuxProcessBase::read (const uint32_t offset, const uint32_t size, uint8_t *target)
{
if(size == 0) return;
ssize_t result;
ssize_t total = 0;
ssize_t remaining = size;
while (total != size)
{
result = pread(memFileHandle, target + total ,remaining,offset + total);
if(result == -1)
{
cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl;
cerr << "errno: " << errno << endl;
errno = 0;
throw Error::MemoryAccessDenied();
}
else
{
total += result;
remaining -= result;
}
}
}
void LinuxProcessBase::readByte (const uint32_t offset, uint8_t &val )
{
read(offset, 1, &val);
}
void LinuxProcessBase::readWord (const uint32_t offset, uint16_t &val)
{
read(offset, 2, (uint8_t *) &val);
}
void LinuxProcessBase::readDWord (const uint32_t offset, uint32_t &val)
{
read(offset, 4, (uint8_t *) &val);
}
void LinuxProcessBase::readFloat (const uint32_t offset, float &val)
{
read(offset, 4, (uint8_t *) &val);
}
void LinuxProcessBase::readQuad (const uint32_t offset, uint64_t &val)
{
read(offset, 8, (uint8_t *) &val);
}
/*
* WRITING
*/
void LinuxProcessBase::writeQuad (uint32_t offset, const uint64_t data)
{
#ifdef HAVE_64_BIT
ptrace(PTRACE_POKEDATA,my_pid, offset, data);
#else
ptrace(PTRACE_POKEDATA,my_pid, offset, (uint32_t) data);
ptrace(PTRACE_POKEDATA,my_pid, offset+4, (uint32_t) (data >> 32));
#endif
}
void LinuxProcessBase::writeDWord (uint32_t offset, uint32_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = Process::readQuad(offset);
orig &= 0xFFFFFFFF00000000;
orig |= data;
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#else
ptrace(PTRACE_POKEDATA,my_pid, offset, data);
#endif
}
// using these is expensive.
void LinuxProcessBase::writeWord (uint32_t offset, uint16_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = Process::readQuad(offset);
orig &= 0xFFFFFFFFFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#else
uint32_t orig = Process::readDWord(offset);
orig &= 0xFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#endif
}
void LinuxProcessBase::writeByte (uint32_t offset, uint8_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = Process::readQuad(offset);
orig &= 0xFFFFFFFFFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#else
uint32_t orig = Process::readDWord(offset);
orig &= 0xFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#endif
}
// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS
void LinuxProcessBase::write (uint32_t offset, uint32_t size, uint8_t *source)
{
uint32_t indexptr = 0;
while (size > 0)
{
#ifdef HAVE_64_BIT
// quad!
if(size >= 8)
{
writeQuad(offset, *(uint64_t *) (source + indexptr));
offset +=8;
indexptr +=8;
size -=8;
}
else
#endif
// 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 LinuxProcessBase::readCString (uint32_t offset)
{
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = Process::readByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r && counter < 255);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}
string LinuxProcessBase::getPath()
{
char cwd_name[256];
char target_name[1024];
int target_result;
sprintf(cwd_name,"/proc/%d/cwd", getPID());
// resolve /proc/PID/exe link
target_result = readlink(cwd_name, target_name, sizeof(target_name));
target_name[target_result] = '\0';
return(string(target_name));
}

@ -22,7 +22,9 @@ must not be misrepresented as being the original software.
distribution.
*/
#include "Internal.h"
#include "dfhack/DFProcess.h"
#include "LinuxProcess.h"
#include "ProcessFactory.h"
#include "MicrosoftSTL.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
#include <errno.h>
@ -30,37 +32,30 @@ distribution.
#include <stdio.h>
using namespace DFHack;
class WineProcess::Private
{
public:
Private(Process * self_)
{
my_descriptor = NULL;
my_handle = NULL;
my_pid = 0;
attached = false;
suspended = false;
memFileHandle = 0;
self = self_;
namespace {
class WineProcess : public LinuxProcessBase
{
private:
MicrosoftSTL stl;
public:
WineProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
const std::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){};
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
private:
bool validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions);
};
~Private(){};
VersionInfo * my_descriptor;
Process * self;
pid_t my_handle;
uint32_t my_pid;
string memFile;
int memFileHandle;
bool attached;
bool suspended;
bool identified;
uint32_t STLSTR_buf_off;
uint32_t STLSTR_size_off;
uint32_t STLSTR_cap_off;
bool validate(char * exe_file, uint32_t pid, char * mem_file, vector <VersionInfo *> & known_versions);
};
}
Process* DFHack::createWineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
{
return new WineProcess(pid, known_versions);
}
WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
: d(new Private(this))
WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions) : LinuxProcessBase(pid)
{
char dir_name [256];
char exe_link_name [256];
@ -70,8 +65,8 @@ WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
char target_name[1024];
int target_result;
d->identified = false;
d->my_descriptor = 0;
identified = false;
my_descriptor = 0;
sprintf(dir_name,"/proc/%d/", pid);
sprintf(exe_link_name,"/proc/%d/exe", pid);
@ -107,27 +102,14 @@ WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
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);
identified = validate(exe_link,pid,mem_name,known_versions);
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* mem_file, std::vector< VersionInfo* >& known_versions)
bool WineProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions)
{
md5wrapper md5;
// get hash of the running DF process
@ -137,490 +119,44 @@ bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file
// iterate over the list of memory locations
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
string thishash;
try
{
thishash = (*it)->getMD5();
}
catch (Error::MissingMemoryDefinition& e)
{
continue;
}
// are the md5 hashes the same?
if(VersionInfo::OS_WINDOWS == (*it)->getOS() && hash == thishash)
{
// keep track of created memory_info object so we can destroy it later
VersionInfo *m = new VersionInfo(**it);
my_descriptor = m;
m->setParentProcess(dynamic_cast<Process *>( self ));
my_handle = my_pid = pid;
// tell WineProcess about the /proc/PID/mem file
memFile = mem_file;
identified = true;
OffsetGroup * strGrp = m->getGroup("string")->getGroup("MSVC");
STLSTR_buf_off = strGrp->getOffset("buffer");
STLSTR_size_off = strGrp->getOffset("size");
STLSTR_cap_off = strGrp->getOffset("capacity");
return true;
}
}
return false;
}
WineProcess::~WineProcess()
{
if(d->attached)
{
detach();
}
// destroy our copy of the memory descriptor
if(d->my_descriptor)
delete d->my_descriptor;
delete d;
}
VersionInfo * WineProcess::getDescriptor()
{
return d->my_descriptor;
}
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(d->attached)
{
if(!d->suspended)
return suspend();
return true;
}
// 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 << d->memFile << endl;
cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl;
perror("open(memFile.c_str(),O_RDONLY)");
return false;
}
else
{
d->attached = true;
d->memFileHandle = proc_pid_mem;
return true; // we are attached
}
}
bool WineProcess::detach()
{
if(!d->attached) return true;
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;
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;
ssize_t total = 0;
ssize_t remaining = size;
while (total != size)
{
result = pread(d->memFileHandle, target + total ,remaining,offset + total);
if(result == -1)
{
cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl;
cerr << "errno: " << errno << endl;
errno = 0;
throw Error::MemoryAccessDenied();
}
else
{
total += result;
remaining -= 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);
}
float WineProcess::readFloat (const uint32_t offset)
{
float val;
read(offset, 4, (uint8_t *) &val);
return val;
}
void WineProcess::readFloat (const uint32_t offset, float &val)
{
read(offset, 4, (uint8_t *) &val);
}
void WineProcess::readQuad (const uint32_t offset, uint64_t &val)
{
read(offset, 8, (uint8_t *) &val);
}
uint64_t WineProcess::readQuad (const uint32_t offset)
{
uint64_t val;
read(offset, 8, (uint8_t *) &val);
return val;
}
/*
* WRITING
*/
void WineProcess::writeQuad (uint32_t offset, const uint64_t data)
{
#ifdef HAVE_64_BIT
ptrace(PTRACE_POKEDATA,d->my_handle, offset, data);
#else
ptrace(PTRACE_POKEDATA,d->my_handle, offset, (uint32_t) data);
ptrace(PTRACE_POKEDATA,d->my_handle, offset+4, (uint32_t) (data >> 32));
#endif
}
void WineProcess::writeDWord (uint32_t offset, uint32_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFF00000000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
ptrace(PTRACE_POKEDATA,d->my_handle, offset, data);
#endif
}
// using these is expensive.
void WineProcess::writeWord (uint32_t offset, uint16_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFFFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
uint32_t orig = readDWord(offset);
orig &= 0xFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#endif
}
void WineProcess::writeByte (uint32_t offset, uint8_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFFFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
uint32_t orig = readDWord(offset);
orig &= 0xFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#endif
}
// 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)
{
#ifdef HAVE_64_BIT
// quad!
if(size >= 8)
if (hash == (*it)->getMD5()) // are the md5 hashes the same?
{
writeQuad(offset, *(uint64_t *) (source + indexptr));
offset +=8;
indexptr +=8;
size -=8;
if (OS_WINDOWS == (*it)->getOS())
{
// keep track of created memory_info object so we can destroy it later
my_descriptor = new VersionInfo(**it);
my_descriptor->setParentProcess(this);
// tell Process about the /proc/PID/mem file
memFile = memFile;
identified = true;
stl.init(this);
return true;
}
}
else
#endif
// 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)
catch (Error::AllMemdef&)
{
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;
continue;
}
}
return false;
}
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;
}
size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
uint32_t start_offset = offset + d->STLSTR_buf_off;
size_t length = readDWord(offset + d->STLSTR_size_off);
size_t capacity = readDWord(offset + d->STLSTR_cap_off);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = readDWord(start_offset);// dereference the start offset
read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
return stl.readSTLString(offset, buffer, bufcapacity);
}
const string WineProcess::readSTLString (uint32_t offset)
{
uint32_t start_offset = offset + d->STLSTR_buf_off;
size_t length = readDWord(offset + d->STLSTR_size_off);
size_t capacity = readDWord(offset + d->STLSTR_cap_off);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = readDWord(start_offset);// dereference the start offset
read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
return stl.readSTLString(offset);
}
string WineProcess::readClassName (uint32_t vptr)
{
int rtti = readDWord(vptr - 0x4);
int typeinfo = readDWord(rtti + 0xC);
string raw = readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 2);// trim @@ from end
return raw;
stl.readClassName(vptr);
}

@ -22,42 +22,36 @@ must not be misrepresented as being the original software.
distribution.
*/
#include "Internal.h"
#include "dfhack/DFProcess.h"
#include "LinuxProcess.h"
#include "ProcessFactory.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
#include <errno.h>
#include <sys/ptrace.h>
using namespace DFHack;
class NormalProcess::Private
{
public:
Private(Process * self_)
namespace {
class NormalProcess : public LinuxProcessBase
{
my_descriptor = NULL;
my_handle = NULL;
my_pid = 0;
attached = false;
suspended = false;
memFileHandle = 0;
self = self_;
public:
NormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
const std::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){};
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
private:
bool validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions);
};
~Private(){};
Window* my_window;
VersionInfo * my_descriptor;
pid_t my_handle;
uint32_t my_pid;
string memFile;
int memFileHandle;
bool attached;
bool suspended;
bool identified;
Process * self;
bool validate(char * exe_file, uint32_t pid, char * mem_file, vector <VersionInfo *> & known_versions);
};
}
Process* DFHack::createNormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
{
return new NormalProcess(pid, known_versions);
}
NormalProcess::NormalProcess(uint32_t pid, vector< VersionInfo* >& known_versions)
: d(new Private(this))
NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions) : LinuxProcessBase(pid)
{
char dir_name [256];
char exe_link_name [256];
@ -67,8 +61,8 @@ NormalProcess::NormalProcess(uint32_t pid, vector< VersionInfo* >& known_version
char target_name[1024];
int target_result;
d->identified = false;
d->my_descriptor = 0;
identified = false;
my_descriptor = 0;
sprintf(dir_name,"/proc/%d/", pid);
sprintf(exe_link_name,"/proc/%d/exe", pid);
@ -89,26 +83,12 @@ NormalProcess::NormalProcess(uint32_t pid, vector< VersionInfo* >& known_version
if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0)
{
// create linux process, add it to the vector
d->identified = d->validate(target_name,pid,mem_name,known_versions );
identified = validate(target_name,pid,mem_name,known_versions);
return;
}
}
bool NormalProcess::isSuspended()
{
return d->suspended;
}
bool NormalProcess::isAttached()
{
return d->attached;
}
bool NormalProcess::isIdentified()
{
return d->identified;
}
bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions)
bool NormalProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions)
{
md5wrapper md5;
// get hash of the running DF process
@ -120,29 +100,21 @@ bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFi
{
try
{
//cout << hash << " ?= " << (*it)->getMD5() << endl;
if(hash == (*it)->getMD5()) // are the md5 hashes the same?
if (hash == (*it)->getMD5()) // are the md5 hashes the same?
{
VersionInfo * m = *it;
if (VersionInfo::OS_LINUX == m->getOS())
if (OS_LINUX == (*it)->getOS())
{
VersionInfo *m2 = new VersionInfo(*m);
my_descriptor = m2;
m2->setParentProcess(dynamic_cast<Process *>( self ));
my_handle = my_pid = pid;
// keep track of created memory_info object so we can destroy it later
my_descriptor = new VersionInfo(**it);
my_descriptor->setParentProcess(this);
// tell Process about the /proc/PID/mem file
memFile = memFile;
identified = true;
return true;
}
else
{
// some error happened, continue with next process
continue;
}
// tell NormalProcess about the /proc/PID/mem file
this->memFile = memFile;
identified = true;
return true;
}
}
catch (Error::MissingMemoryDefinition&)
catch (Error::AllMemdef&)
{
continue;
}
@ -150,400 +122,6 @@ bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFi
return false;
}
NormalProcess::~NormalProcess()
{
if(d->attached)
{
detach();
}
// destroy our copy of the memory descriptor
if(d->my_descriptor)
delete d->my_descriptor;
delete d;
}
VersionInfo * NormalProcess::getDescriptor()
{
return d->my_descriptor;
}
int NormalProcess::getPID()
{
return d->my_pid;
}
//FIXME: implement
bool NormalProcess::getThreadIDs(vector<uint32_t> & threads )
{
return false;
}
//FIXME: cross-reference with ELF segment entries?
void NormalProcess::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 NormalProcess::asyncSuspend()
{
return suspend();
}
bool NormalProcess::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 NormalProcess::forceresume()
{
return resume();
}
bool NormalProcess::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 NormalProcess::attach()
{
int status;
if(d->attached)
{
if(!d->suspended)
return suspend();
return true;
}
// 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;
d->memFileHandle = proc_pid_mem;
return true; // we are attached
}
}
bool NormalProcess::detach()
{
if(!d->attached) return true;
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;
return true;
}
}
}
// danger: uses recursion!
void NormalProcess::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 0x" << hex << size << " bytes at address 0x" << offset << endl;
cerr << "errno: " << errno << endl;
errno = 0;
throw Error::MemoryAccessDenied();
}
else
{
this->read(offset + result, size - result, target + result);
}
}
}
uint8_t NormalProcess::readByte (const uint32_t offset)
{
uint8_t val;
read(offset, 1, &val);
return val;
}
void NormalProcess::readByte (const uint32_t offset, uint8_t &val )
{
read(offset, 1, &val);
}
uint16_t NormalProcess::readWord (const uint32_t offset)
{
uint16_t val;
read(offset, 2, (uint8_t *) &val);
return val;
}
void NormalProcess::readWord (const uint32_t offset, uint16_t &val)
{
read(offset, 2, (uint8_t *) &val);
}
uint32_t NormalProcess::readDWord (const uint32_t offset)
{
uint32_t val;
read(offset, 4, (uint8_t *) &val);
return val;
}
void NormalProcess::readDWord (const uint32_t offset, uint32_t &val)
{
read(offset, 4, (uint8_t *) &val);
}
float NormalProcess::readFloat (const uint32_t offset)
{
float val;
read(offset, 4, (uint8_t *) &val);
return val;
}
void NormalProcess::readFloat (const uint32_t offset, float &val)
{
read(offset, 4, (uint8_t *) &val);
}
uint64_t NormalProcess::readQuad (const uint32_t offset)
{
uint64_t val;
read(offset, 8, (uint8_t *) &val);
return val;
}
void NormalProcess::readQuad (const uint32_t offset, uint64_t &val)
{
read(offset, 8, (uint8_t *) &val);
}
/*
* WRITING
*/
void NormalProcess::writeQuad (uint32_t offset, const uint64_t data)
{
#ifdef HAVE_64_BIT
ptrace(PTRACE_POKEDATA,d->my_handle, offset, data);
#else
ptrace(PTRACE_POKEDATA,d->my_handle, offset, (uint32_t) data);
ptrace(PTRACE_POKEDATA,d->my_handle, offset+4, (uint32_t) (data >> 32));
#endif
}
void NormalProcess::writeDWord (uint32_t offset, uint32_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFF00000000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
ptrace(PTRACE_POKEDATA,d->my_handle, offset, data);
#endif
}
// using these is expensive.
void NormalProcess::writeWord (uint32_t offset, uint16_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFFFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
uint32_t orig = readDWord(offset);
orig &= 0xFFFF0000;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#endif
}
void NormalProcess::writeByte (uint32_t offset, uint8_t data)
{
#ifdef HAVE_64_BIT
uint64_t orig = readQuad(offset);
orig &= 0xFFFFFFFFFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#else
uint32_t orig = readDWord(offset);
orig &= 0xFFFFFF00;
orig |= data;
ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig);
#endif
}
// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS
void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source)
{
uint32_t indexptr = 0;
while (size > 0)
{
#ifdef HAVE_64_BIT
// quad!
if(size >= 8)
{
writeQuad(offset, *(uint64_t *) (source + indexptr));
offset +=8;
indexptr +=8;
size -=8;
}
else
#endif
// 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 NormalProcess::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;
}
struct _Rep_base
{
uint32_t _M_length;
@ -554,7 +132,7 @@ struct _Rep_base
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
_Rep_base header;
offset = readDWord(offset);
offset = Process::readDWord(offset);
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
read(offset,read_real,(uint8_t * )buffer);
@ -566,7 +144,7 @@ const string NormalProcess::readSTLString (uint32_t offset)
{
_Rep_base header;
offset = readDWord(offset);
offset = Process::readDWord(offset);
read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
// FIXME: use char* everywhere, avoid string
@ -579,8 +157,8 @@ const string NormalProcess::readSTLString (uint32_t offset)
string NormalProcess::readClassName (uint32_t vptr)
{
int typeinfo = readDWord(vptr - 0x4);
int typestring = readDWord(typeinfo + 0x4);
int typeinfo = Process::readDWord(vptr - 0x4);
int typestring = Process::readDWord(typeinfo + 0x4);
string raw = readCString(typestring);
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
size_t end = raw.length();

@ -22,68 +22,25 @@ must not be misrepresented as being the original software.
distribution.
*/
#include "Internal.h"
#include "dfhack/DFProcess.h"
#include "SHMProcess.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
#include "shms.h"
#include "mod-core.h"
using namespace DFHack;
// a full memory barrier! better be safe than sorry.
class SHMProcess::Private
SHMProcess::Private::Private(SHMProcess * self_)
{
public:
Private()
{
memdescriptor = NULL;
process_ID = 0;
shm_addr = 0;
attached = false;
locked = false;
identified = false;
useYield = 0;
DFSVMutex = 0;
DFCLMutex = 0;
DFCLSuspendMutex = 0;
attachmentIdx = -1;
};
~Private(){};
VersionInfo * memdescriptor;
SHMProcess * self;
uint32_t process_ID;
char *shm_addr;
HANDLE DFSVMutex;
HANDLE DFCLMutex;
HANDLE DFCLSuspendMutex;
int attachmentIdx;
bool attached;
bool locked;
bool identified;
bool useYield;
bool validate(std::vector< VersionInfo* >& known_versions);
bool Aux_Core_Attach(bool & versionOK, uint32_t & PID);
bool SetAndWait (uint32_t state);
bool GetLocks();
bool AreLocksOk();
void FreeLocks();
};
// some helpful macros to keep the code bloat in check
#define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx]
#define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx]
#define SHMHDR ((shm_core_hdr *)shm_addr)
#define D_SHMHDR ((shm_core_hdr *)(d->shm_addr))
#define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER))
#define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER))
bool SHMProcess::SetAndWait (uint32_t state)
{
return d->SetAndWait(state);
memdescriptor = NULL;
process_ID = 0;
attached = false;
locked = false;
identified = false;
useYield = 0;
DFSVMutex = 0;
DFCLMutex = 0;
DFCLSuspendMutex = 0;
self = self_;
}
bool SHMProcess::Private::SetAndWait (uint32_t state)
@ -116,6 +73,7 @@ bool SHMProcess::Private::SetAndWait (uint32_t state)
}
cnt++;
}
// server returned a generic error
if(SHMCMD == CORE_ERROR)
{
return false;
@ -123,6 +81,11 @@ bool SHMProcess::Private::SetAndWait (uint32_t state)
return true;
}
bool SHMProcess::SetAndWait (uint32_t state)
{
return d->SetAndWait(state);
}
uint32_t OS_getAffinity()
{
HANDLE hProcess = GetCurrentProcess();
@ -253,71 +216,10 @@ bool SHMProcess::Private::AreLocksOk()
return false;
}
/*
char svmutexname [256];
char clmutexname [256];
sprintf(clmutexname,"DFCLMutex-%d",PID);
// get server and client mutex
d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, svmutexname);
if(d->DFSVMutex == 0)
{
return;
}
d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, clmutexname);
if(d->DFCLMutex == 0)
{
return;
}
*/
SHMProcess::SHMProcess(uint32_t PID, vector <VersionInfo *> & known_versions)
: d(new Private())
{
d->process_ID = PID;
d->self = this;
// attach the SHM
if(!attach())
{
return;
}
// Test bridge version, get PID, sync Yield
bool bridgeOK;
if(!d->Aux_Core_Attach(bridgeOK,d->process_ID))
{
detach();
throw Error::SHMAttachFailure();
}
else if(!bridgeOK)
{
detach();
throw Error::SHMVersionMismatch();
}
d->validate(known_versions);
// at this point, DF is attached and suspended, make it run
detach();
}
bool SHMProcess::isSuspended()
{
return d->locked;
}
bool SHMProcess::isAttached()
{
return d->attached;
}
bool SHMProcess::isIdentified()
{
return d->identified;
}
bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
{
// try to identify the DF version
IMAGE_NT_HEADERS32 pe_header;
IMAGE_NT_HEADERS pe_header;
IMAGE_SECTION_HEADER sections[16];
HMODULE hmod = NULL;
DWORD junk;
@ -340,7 +242,7 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
uint32_t base = (uint32_t)hmod;
// read from this process
uint32_t pe_offset = self->readDWord(base+0x3C);
uint32_t pe_offset = self->Process::readDWord(base+0x3C);
self->read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
self->read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections );
@ -353,7 +255,7 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
{
pe_timestamp = (*it)->getPE();
}
catch(Error::MissingMemoryDefinition&)
catch(Error::AllMemdef&)
{
continue;
}
@ -371,29 +273,6 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
}
return false;
}
SHMProcess::~SHMProcess()
{
if(d->attached)
{
detach();
}
// destroy data model. this is assigned by processmanager
if(d->memdescriptor)
{
delete d->memdescriptor;
}
delete d;
}
VersionInfo * SHMProcess::getDescriptor()
{
return d->memdescriptor;
}
int SHMProcess::getPID()
{
return d->process_ID;
}
bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
{
@ -428,137 +307,18 @@ bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries
void SHMProcess::getMemRanges( vector<t_memrange> & ranges )
{
// code here is taken from hexsearch by Silas Dunmore.
// As this IMHO isn't a 'sunstantial portion' of anything, I'm not including the MIT license here
// I'm faking this, because there's no way I'm using VirtualQuery
t_memrange temp;
uint32_t base = d->memdescriptor->getBase();
temp.start = base + 0x1000; // more fakery.
temp.end = base + readDWord(base+readDWord(base+0x3C)+0x50)-1; // yay for magic.
temp.read = 1;
temp.write = 1;
temp.execute = 0; // fake
strcpy(temp.name,"pants");
ranges.push_back(temp);
// BLAH
ranges.clear();
}
bool SHMProcess::suspend()
bool SHMProcess::acquireSuspendLock()
{
if(!d->attached)
{
return false;
}
if(d->locked)
{
return true;
}
//cerr << "suspend" << endl;// FIXME: throw
// FIXME: this should be controlled on the server side
// FIXME: IF server got CORE_RUN in this frame, interpret CORE_SUSPEND as CORE_STEP
// did we just resume a moment ago?
if(D_SHMCMD == CORE_RUN)
{
//fprintf(stderr,"%d invokes step\n",d->attachmentIdx);
// wait for the next window
/*
if(!d->SetAndWait(CORE_STEP))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))");
}
*/
D_SHMCMD = CORE_STEP;
}
else
{
//fprintf(stderr,"%d invokes suspend\n",d->attachmentIdx);
// lock now
/*
if(!d->SetAndWait(CORE_SUSPEND))
{
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))");
}
*/
D_SHMCMD = CORE_SUSPEND;
}
//fprintf(stderr,"waiting for lock\n");
// we wait for the server to give up our suspend lock (held by default)
if( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 )
{
d->locked = true;
return true;
}
return false;
}
// FIXME: needs a good think-through
bool SHMProcess::asyncSuspend()
{
if(!d->attached)
{
return false;
}
if(d->locked)
{
return true;
}
//cerr << "async suspend" << endl;// FIXME: throw
uint32_t cmd = D_SHMCMD;
if(cmd == CORE_SUSPENDED)
{
// we have to hold the lock to be really suspended
if( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 )
{
d->locked = true;
return true;
}
return false;
}
else
{
// did we just resume a moment ago?
if(cmd == CORE_STEP)
{
return false;
}
else if(cmd == CORE_RUN)
{
D_SHMCMD = CORE_STEP;
}
else
{
D_SHMCMD = CORE_SUSPEND;
}
return false;
}
return ( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 );
}
bool SHMProcess::forceresume()
bool SHMProcess::releaseSuspendLock()
{
return resume();
}
// FIXME: wait for the server to advance a step!
bool SHMProcess::resume()
{
if(!d->attached)
return false;
if(!d->locked)
return true;
//cerr << "resume" << endl;// FIXME: throw
// unlock the suspend lock
if( ReleaseMutex(d->DFCLSuspendMutex) != 0)
{
d->locked = false;
if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds!
{
return true;
}
throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))");
}
throw Error::SHMLockingError("if( ReleaseMutex(d->DFCLSuspendMutex) != 0)");
return false;
return ( ReleaseMutex(d->DFCLSuspendMutex) != 0);
}
@ -576,21 +336,6 @@ bool SHMProcess::attach()
//cerr << "server is full or not really there!" << endl;
return false;
}
/*
// check if DF is there
if(!d->isValidSV())
{
return false; // NOT
}
*/
/*
// try locking client mutex
uint32_t result = WaitForSingleObject(d->DFCLMutex,0);
if( result != WAIT_OBJECT_0 && result != WAIT_ABANDONED)
{
return false; // we couldn't lock it
}
*/
/*
* Locate the segment.
@ -633,12 +378,10 @@ bool SHMProcess::attach()
bool SHMProcess::detach()
{
if(!d->attached) return true;
//cerr << "detach" << endl;// FIXME: throw
if(d->locked)
{
resume();
}
//cerr << "detach after resume" << endl;// FIXME: throw
// detach segment
UnmapViewOfFile(d->shm_addr);
// release it for some other client
@ -650,330 +393,30 @@ bool SHMProcess::detach()
return true;
}
void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal read under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = src_address;
D_SHMHDR->length = size;
full_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void),size);
}
// a big read, we pull data over the shm in iterations
else
{
// first read equals the size of the SHM window
uint32_t to_read = SHM_BODY;
while (size)
{
// read to_read bytes from src_cursor
D_SHMHDR->address = src_address;
D_SHMHDR->length = to_read;
full_barrier
d->SetAndWait(CORE_READ);
memcpy (target_buffer, D_SHMDATA(void) ,to_read);
// decrease size by bytes read
size -= to_read;
// move the cursors
src_address += to_read;
target_buffer += to_read;
// check how much to write in the next iteration
to_read = min(size, (uint32_t) SHM_BODY);
}
}
}
uint8_t SHMProcess::readByte (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_BYTE);
return D_SHMHDR->value;
}
void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_BYTE);
val = D_SHMHDR->value;
}
uint16_t SHMProcess::readWord (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_WORD);
return D_SHMHDR->value;
}
void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_WORD);
val = D_SHMHDR->value;
}
uint32_t SHMProcess::readDWord (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
return D_SHMHDR->value;
}
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
val = D_SHMHDR->value;
}
float SHMProcess::readFloat (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
return reinterpret_cast<float&> (D_SHMHDR->value);
}
void SHMProcess::readFloat (const uint32_t offset, float &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_DWORD);
val = reinterpret_cast<float&> (D_SHMHDR->value);
}
uint64_t SHMProcess::readQuad (const uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_QUAD);
return D_SHMHDR->Qvalue;
}
void SHMProcess::readQuad (const uint32_t offset, uint64_t &val)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_QUAD);
val = D_SHMHDR->Qvalue;
}
/*
* WRITING
*/
void SHMProcess::writeQuad (uint32_t offset, uint64_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->Qvalue = data;
full_barrier
d->SetAndWait(CORE_WRITE_QUAD);
}
void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_DWORD);
}
// using these is expensive.
void SHMProcess::writeWord (uint32_t offset, uint16_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_WORD);
}
void SHMProcess::writeByte (uint32_t offset, uint8_t data)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
D_SHMHDR->value = data;
full_barrier
d->SetAndWait(CORE_WRITE_BYTE);
}
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
{
if(!d->locked) throw Error::MemoryAccessDenied();
// normal write under 1MB
if(size <= SHM_BODY)
{
D_SHMHDR->address = dst_address;
D_SHMHDR->length = size;
memcpy(D_SHMDATA(void),source_buffer, size);
full_barrier
d->SetAndWait(CORE_WRITE);
}
// a big write, we push this over the shm in iterations
else
{
// first write equals the size of the SHM window
uint32_t to_write = SHM_BODY;
while (size)
{
// write to_write bytes to dst_cursor
D_SHMHDR->address = dst_address;
D_SHMHDR->length = to_write;
memcpy(D_SHMDATA(void),source_buffer, to_write);
full_barrier
d->SetAndWait(CORE_WRITE);
// decrease size by bytes written
size -= to_write;
// move the cursors
source_buffer += to_write;
dst_address += to_write;
// check how much to write in the next iteration
to_write = min(size, (uint32_t) SHM_BODY);
}
}
}
// FIXME: butt-fugly
const std::string SHMProcess::readCString (uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
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;
}
const std::string SHMProcess::readSTLString(uint32_t offset)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
return(string( D_SHMDATA(char) ));
}
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = offset;
full_barrier
d->SetAndWait(CORE_READ_STL_STRING);
size_t length = D_SHMHDR->value;
size_t fit = min(bufcapacity - 1, length);
strncpy(buffer,D_SHMDATA(char),fit);
buffer[fit] = 0;
return fit;
}
void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
{
if(!d->locked) throw Error::MemoryAccessDenied();
D_SHMHDR->address = address;
strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
full_barrier
d->SetAndWait(CORE_WRITE_STL_STRING);
}
string SHMProcess::readClassName (uint32_t vptr)
{
int rtti = readDWord(vptr - 0x4);
int typeinfo = readDWord(rtti + 0xC);
int rtti = Process::readDWord(vptr - 0x4);
int typeinfo = Process::readDWord(rtti + 0xC);
string raw = readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 2);// trim @@ from end
return raw;
}
// get module index by name and version. bool 0 = error
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
string SHMProcess::getPath()
{
if(!d->locked) throw Error::MemoryAccessDenied();
modulelookup * payload = D_SHMDATA(modulelookup);
payload->version = version;
strncpy(payload->name,name,255);
payload->name[255] = 0;
if(!SetAndWait(CORE_ACQUIRE_MODULE))
{
return false; // FIXME: throw a fatal exception instead
}
if(D_SHMHDR->error)
{
return false;
}
//fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value);
OUTPUT = D_SHMHDR->value;
return true;
HMODULE hmod;
DWORD junk;
char String[255];
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->process_ID ); //get the handle from the process ID
EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle
GetModuleFileNameEx(hProcess,hmod,String,sizeof(String)); //get the filename from the module
string out(String);
return(out.substr(0,out.find_last_of("\\")));
}
char * SHMProcess::getSHMStart (void)
{
if(!d->locked) throw Error::MemoryAccessDenied();
return /*d->shm_addr_with_cl_idx*/ d->shm_addr;
}
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, uint32_t & PID)
{
if(!locked) throw Error::MemoryAccessDenied();
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
if(!SetAndWait(CORE_ATTACH)) return false;
/*
cerr <<"CORE_VERSION" << CORE_VERSION << endl;
cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl;
*/
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
PID = SHMDATA(coreattach)->sv_PID;
useYield = SHMDATA(coreattach)->sv_useYield;
#ifdef DEBUG
if(useYield) cerr << "Using Yield!" << endl;
#endif
return true;
return d->shm_addr;
}

@ -22,79 +22,136 @@ must not be misrepresented as being the original software.
distribution.
*/
#include "Internal.h"
#include "dfhack/DFProcess.h"
#include "ProcessFactory.h"
#include "MicrosoftSTL.h"
#include "dfhack/VersionInfo.h"
#include "dfhack/DFError.h"
#include <string.h>
using namespace DFHack;
class NormalProcess::Private
namespace
{
public:
Private()
{
my_descriptor = NULL;
my_handle = NULL;
my_main_thread = NULL;
my_pid = 0;
attached = false;
suspended = false;
};
~Private(){};
VersionInfo * my_descriptor;
HANDLE my_handle;
HANDLE my_main_thread;
uint32_t my_pid;
string memFile;
bool attached;
bool suspended;
bool identified;
uint32_t STLSTR_buf_off;
uint32_t STLSTR_size_off;
uint32_t STLSTR_cap_off;
};
class NormalProcess : public Process
{
private:
VersionInfo * my_descriptor;
HANDLE my_handle;
HANDLE my_main_thread;
uint32_t my_pid;
string memFile;
bool attached;
bool suspended;
bool identified;
IMAGE_NT_HEADERS pe_header;
IMAGE_SECTION_HEADER * sections;
uint32_t base;
MicrosoftSTL stl;
public:
NormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
~NormalProcess();
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
void readFloat(const uint32_t address, float & value);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::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){};
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
VersionInfo *getDescriptor();
int getPID();
std::string getPath();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { OUTPUT=0; return false;};
// get the SHM start if available
char * getSHMStart (void){return 0;};
// set a SHM command and wait for a response
bool SetAndWait (uint32_t state){return false;};
};
}
Process* DFHack::createNormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
{
return new NormalProcess(pid, known_versions);
}
NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
: d(new Private())
: my_pid(pid)
{
my_descriptor = NULL;
my_main_thread = NULL;
attached = false;
suspended = false;
base = 0;
sections = 0;
HMODULE hmod = NULL;
DWORD junk;
HANDLE hProcess;
DWORD needed;
bool found = false;
IMAGE_NT_HEADERS32 pe_header;
IMAGE_SECTION_HEADER sections[16];
d->identified = false;
identified = false;
// open process
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid );
if (NULL == hProcess)
my_handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, my_pid );
if (NULL == my_handle)
return;
// try getting the first module of the process
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0)
if(EnumProcessModules(my_handle, &hmod, sizeof(hmod), &needed) == 0)
{
CloseHandle(hProcess);
CloseHandle(my_handle);
// cout << "EnumProcessModules fail'd" << endl;
return; //if enumprocessModules fails, give up
}
// got base ;)
uint32_t base = (uint32_t)hmod;
base = (uint32_t)hmod;
// temporarily assign this to allow some checks
d->my_handle = hProcess;
d->my_main_thread = 0;
my_main_thread = 0;
// read from this process
try
{
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 );
d->my_handle = 0;
uint32_t pe_offset = Process::readDWord(base+0x3C);
read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * pe_header.FileHeader.NumberOfSections;
sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize);
read(base + pe_offset + sizeof(pe_header), sectionsSize, (uint8_t *)sections);
my_handle = 0;
}
catch (exception &)
{
CloseHandle(hProcess);
d->my_handle = 0;
CloseHandle(my_handle);
my_handle = 0;
return;
}
@ -103,7 +160,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
// filter by OS
if(VersionInfo::OS_WINDOWS != (*it)->getOS())
if(OS_WINDOWS != (*it)->getOS())
continue;
uint32_t pe_timestamp;
// filter by timestamp, skip entries without a timestamp
@ -111,7 +168,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
{
pe_timestamp = (*it)->getPE();
}
catch(Error::MissingMemoryDefinition&)
catch(Error::AllMemdef&)
{
continue;
}
@ -121,26 +178,21 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
// all went well
{
printf("Match found! Using version %s.\n", (*it)->getVersion().c_str());
d->identified = true;
identified = true;
// give the process a data model and memory layout fixed for the base of first module
VersionInfo *m = new VersionInfo(**it);
m->RebaseAll(base);
my_descriptor = new VersionInfo(**it);
my_descriptor->RebaseAll(base);
// keep track of created memory_info object so we can destroy it later
d->my_descriptor = m;
m->setParentProcess(this);
my_descriptor->setParentProcess(this);
// process is responsible for destroying its data model
d->my_pid = pid;
d->my_handle = hProcess;
d->identified = true;
my_handle = my_handle;
identified = true;
// TODO: detect errors in thread enumeration
vector<uint32_t> threads;
getThreadIDs( threads );
d->my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]);
OffsetGroup * strGrp = m->getGroup("string")->getGroup("MSVC");
d->STLSTR_buf_off = strGrp->getOffset("buffer");
d->STLSTR_size_off = strGrp->getOffset("size");
d->STLSTR_cap_off = strGrp->getOffset("capacity");
my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]);
stl.init(this);
found = true;
break; // break the iterator loop
}
@ -148,7 +200,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
// close handle of processes that aren't DF
if(!found)
{
CloseHandle(hProcess);
CloseHandle(my_handle);
}
}
/*
@ -156,45 +208,46 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
NormalProcess::~NormalProcess()
{
if(d->attached)
if(attached)
{
detach();
}
// destroy our rebased copy of the memory descriptor
delete d->my_descriptor;
if(d->my_handle != NULL)
delete my_descriptor;
if(my_handle != NULL)
{
CloseHandle(d->my_handle);
CloseHandle(my_handle);
}
if(d->my_main_thread != NULL)
if(my_main_thread != NULL)
{
CloseHandle(d->my_main_thread);
CloseHandle(my_main_thread);
}
delete d;
if(sections != NULL)
free(sections);
}
VersionInfo * NormalProcess::getDescriptor()
{
return d->my_descriptor;
return my_descriptor;
}
int NormalProcess::getPID()
{
return d->my_pid;
return my_pid;
}
bool NormalProcess::isSuspended()
{
return d->suspended;
return suspended;
}
bool NormalProcess::isAttached()
{
return d->attached;
return attached;
}
bool NormalProcess::isIdentified()
{
return d->identified;
return identified;
}
bool NormalProcess::asyncSuspend()
@ -204,49 +257,49 @@ bool NormalProcess::asyncSuspend()
bool NormalProcess::suspend()
{
if(!d->attached)
if(!attached)
return false;
if(d->suspended)
if(suspended)
{
return true;
}
SuspendThread(d->my_main_thread);
d->suspended = true;
SuspendThread(my_main_thread);
suspended = true;
return true;
}
bool NormalProcess::forceresume()
{
if(!d->attached)
if(!attached)
return false;
while (ResumeThread(d->my_main_thread) > 1);
d->suspended = false;
while (ResumeThread(my_main_thread) > 1);
suspended = false;
return true;
}
bool NormalProcess::resume()
{
if(!d->attached)
if(!attached)
return false;
if(!d->suspended)
if(!suspended)
{
return true;
}
ResumeThread(d->my_main_thread);
d->suspended = false;
ResumeThread(my_main_thread);
suspended = false;
return true;
}
bool NormalProcess::attach()
{
if(d->attached)
if(attached)
{
if(!d->suspended)
if(!suspended)
return suspend();
return true;
}
d->attached = true;
attached = true;
suspend();
return true;
@ -255,9 +308,9 @@ bool NormalProcess::attach()
bool NormalProcess::detach()
{
if(!d->attached) return true;
if(!attached) return true;
resume();
d->attached = false;
attached = false;
return true;
}
@ -281,7 +334,7 @@ bool NormalProcess::getThreadIDs(vector<uint32_t> & threads )
do
{
if( te32.th32OwnerProcessID == d->my_pid )
if( te32.th32OwnerProcessID == my_pid )
{
threads.push_back(te32.th32ThreadID);
}
@ -290,143 +343,200 @@ bool NormalProcess::getThreadIDs(vector<uint32_t> & threads )
CloseHandle( AllThreads );
return true;
}
//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries
void NormalProcess::getMemRanges( vector<t_memrange> & ranges )
/*
typedef struct _MEMORY_BASIC_INFORMATION
{
void * BaseAddress;
void * AllocationBase;
uint32_t AllocationProtect;
size_t RegionSize;
uint32_t State;
uint32_t Protect;
uint32_t Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
*/
/*
//Internal structure used to store heap block information.
struct HeapBlock
{
// code here is taken from hexsearch by Silas Dunmore.
// As this IMHO isn't a 'sunstantial portion' of anything, I'm not including the MIT license here
// I'm faking this, because there's no way I'm using VirtualQuery
t_memrange temp;
uint32_t base = d->my_descriptor->getBase();
temp.start = base + 0x1000; // more fakery.
temp.end = base + readDWord(base+readDWord(base+0x3C)+0x50)-1; // yay for magic.
temp.read = 1;
temp.write = 1;
temp.execute = 0; // fake
strcpy(temp.name,"pants");// that's right. I'm calling it pants. Windows can go to HELL
ranges.push_back(temp);
PVOID dwAddress;
DWORD dwSize;
DWORD dwFlags;
ULONG reserved;
};
*/
void HeapNodes(DWORD pid, map<uint64_t, unsigned int> & heaps)
{
// Create debug buffer
PDEBUG_BUFFER db = RtlCreateQueryDebugBuffer(0, FALSE);
// Get process heap data
RtlQueryProcessDebugInformation( pid, PDI_HEAPS/* | PDI_HEAP_BLOCKS*/, db);
ULONG heapNodeCount = db->HeapInformation ? *PULONG(db->HeapInformation):0;
PDEBUG_HEAP_INFORMATION heapInfo = PDEBUG_HEAP_INFORMATION(PULONG(db-> HeapInformation) + 1);
// Go through each of the heap nodes and dispaly the information
for (unsigned int i = 0; i < heapNodeCount; i++)
{
heaps[heapInfo[i].Base] = i;
}
// Clean up the buffer
RtlDestroyQueryDebugBuffer( db );
}
uint8_t NormalProcess::readByte (const uint32_t offset)
// FIXME: NEEDS TESTING!
void NormalProcess::getMemRanges( vector<t_memrange> & ranges )
{
uint8_t result;
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL))
throw Error::MemoryAccessDenied();
return result;
MEMORY_BASIC_INFORMATION MBI;
map<uint64_t, unsigned int> heaps;
uint64_t movingStart = 0;
map <uint64_t, string> nameMap;
// get page size
SYSTEM_INFO si;
GetSystemInfo(&si);
uint64_t PageSize = si.dwPageSize;
// enumerate heaps
HeapNodes(my_pid, heaps);
// go through all the VM regions, convert them to our internal format
while (VirtualQueryEx(this->my_handle, (const void*) (movingStart), &MBI, sizeof(MBI)) == sizeof(MBI))
{
movingStart = ((uint64_t)MBI.BaseAddress + MBI.RegionSize);
if(movingStart % PageSize != 0)
movingStart = (movingStart / PageSize + 1) * PageSize;
// skip empty regions and regions we share with other processes (DLLs)
if( !(MBI.State & MEM_COMMIT) /*|| !(MBI.Type & MEM_PRIVATE)*/ )
continue;
t_memrange temp;
temp.start = (uint64_t) MBI.BaseAddress;
temp.end = ((uint64_t)MBI.BaseAddress + (uint64_t)MBI.RegionSize);
temp.read = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READONLY || MBI.Protect & PAGE_READWRITE;
temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READWRITE;
temp.execute = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_EXECUTE;
temp.valid = true;
if(!GetModuleBaseName(this->my_handle, (HMODULE) temp.start, temp.name, 1024))
{
if(nameMap.count(temp.start))
{
// potential buffer overflow...
strcpy(temp.name, nameMap[temp.start].c_str());
}
else
{
// filter away shared segments without a name.
if( !(MBI.Type & MEM_PRIVATE) )
continue;
else
{
// could be a heap?
if(heaps.count(temp.start))
{
sprintf(temp.name,"HEAP %d",heaps[temp.start]);
}
else temp.name[0]=0;
}
}
}
else
{
// this is our executable! (could be generalized to pull segments from libs, but whatever)
if(base == temp.start)
{
for(int i = 0; i < pe_header.FileHeader.NumberOfSections; i++)
{
char sectionName[9];
memcpy(sectionName,sections[i].Name,8);
sectionName[8] = 0;
string nm;
nm.append(temp.name);
nm.append(" : ");
nm.append(sectionName);
nameMap[temp.start + sections[i].VirtualAddress] = nm;
}
}
else
continue;
}
ranges.push_back(temp);
}
}
void NormalProcess::readByte (const uint32_t offset,uint8_t &result)
{
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL))
throw Error::MemoryAccessDenied();
}
uint16_t NormalProcess::readWord (const uint32_t offset)
{
uint16_t result;
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL))
if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint8_t), NULL))
throw Error::MemoryAccessDenied();
return result;
}
void NormalProcess::readWord (const uint32_t offset, uint16_t &result)
{
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL))
if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint16_t), NULL))
throw Error::MemoryAccessDenied();
}
uint32_t NormalProcess::readDWord (const uint32_t offset)
{
uint32_t result;
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL))
throw Error::MemoryAccessDenied();
return result;
}
void NormalProcess::readDWord (const uint32_t offset, uint32_t &result)
{
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL))
throw Error::MemoryAccessDenied();
}
uint64_t NormalProcess::readQuad (const uint32_t offset)
{
uint64_t result;
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint64_t), NULL))
if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint32_t), NULL))
throw Error::MemoryAccessDenied();
return result;
}
void NormalProcess::readQuad (const uint32_t offset, uint64_t &result)
{
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint64_t), NULL))
if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(uint64_t), NULL))
throw Error::MemoryAccessDenied();
}
float NormalProcess::readFloat (const uint32_t offset)
{
float result;
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(float), NULL))
throw Error::MemoryAccessDenied();
return result;
}
void NormalProcess::readFloat (const uint32_t offset, float &result)
{
if(!ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(float), NULL))
if(!ReadProcessMemory(my_handle, (int*) offset, &result, sizeof(float), NULL))
throw Error::MemoryAccessDenied();
}
void NormalProcess::read (const uint32_t offset, uint32_t size, uint8_t *target)
{
if(!ReadProcessMemory(d->my_handle, (int*) offset, target, size, NULL))
if(!ReadProcessMemory(my_handle, (int*) offset, target, size, NULL))
throw Error::MemoryAccessDenied();
}
// WRITING
void NormalProcess::writeQuad (const uint32_t offset, uint64_t data)
{
if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL))
if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
throw Error::MemoryAccessDenied();
}
void NormalProcess::writeDWord (const uint32_t offset, uint32_t data)
{
if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL))
if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
throw Error::MemoryAccessDenied();
}
// using these is expensive.
void NormalProcess::writeWord (uint32_t offset, uint16_t data)
{
if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL))
if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
throw Error::MemoryAccessDenied();
}
void NormalProcess::writeByte (uint32_t offset, uint8_t data)
{
if(!WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(data), NULL))
if(!WriteProcessMemory(my_handle, (int*) offset, &data, sizeof(data), NULL))
throw Error::MemoryAccessDenied();
}
void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source)
{
if(!WriteProcessMemory(d->my_handle, (int*) offset, source, size, NULL))
if(!WriteProcessMemory(my_handle, (int*) offset, source, size, NULL))
throw Error::MemoryAccessDenied();
}
///FIXME: reduce use of temporary objects
const string NormalProcess::readCString (const uint32_t offset)
{
string temp;
char temp_c[256];
SIZE_T read;
if(!ReadProcessMemory(d->my_handle, (int *) offset, temp_c, 254, &read))
if(!ReadProcessMemory(my_handle, (int *) offset, temp_c, 254, &read))
throw Error::MemoryAccessDenied();
// needs to be 254+1 byte for the null term
temp_c[read+1] = 0;
@ -436,55 +546,26 @@ const string NormalProcess::readCString (const uint32_t offset)
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
uint32_t start_offset = offset + d->STLSTR_buf_off;
size_t length = readDWord(offset + d->STLSTR_size_off);
size_t capacity = readDWord(offset + d->STLSTR_cap_off);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = readDWord(start_offset);// dereference the start offset
read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
return stl.readSTLString(offset, buffer, bufcapacity);
}
const string NormalProcess::readSTLString (uint32_t offset)
{
uint32_t start_offset = offset + d->STLSTR_buf_off;
size_t length = readDWord(offset + d->STLSTR_size_off);
size_t capacity = readDWord(offset + d->STLSTR_cap_off);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = readDWord(start_offset);// dereference the start offset
read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
return stl.readSTLString(offset);
}
string NormalProcess::readClassName (uint32_t vptr)
{
int rtti = readDWord(vptr - 0x4);
int typeinfo = readDWord(rtti + 0xC);
string raw = readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 2);// trim @@ from end
return raw;
return stl.readClassName(vptr);
}
string NormalProcess::getPath()
{
HMODULE hmod;
DWORD junk;
char String[255];
EnumProcessModules(my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle
GetModuleFileNameEx(my_handle,hmod,String,sizeof(String)); //get the filename from the module
string out(String);
return(out.substr(0,out.find_last_of("\\")));
}

@ -23,10 +23,10 @@ distribution.
*/
#include "Internal.h"
#include "ProcessFactory.h"
#include "dfhack/VersionInfoFactory.h"
#include "dfhack/DFProcessEnumerator.h"
#include "dfhack/DFProcess.h"
#include "dfhack/VersionInfo.h"
@ -63,7 +63,7 @@ BadProcesses::~BadProcesses()
bool BadProcesses::Contains(Process* p)
{
for(int i = 0; i < d->bad.size(); i++)
for(unsigned int i = 0; i < d->bad.size(); i++)
{
if(d->bad[i] == p)
return true;
@ -96,7 +96,7 @@ uint32_t BadProcesses::size()
void BadProcesses::clear()
{
for(int i = 0; i < d->bad.size(); i++)
for(unsigned int i = 0; i < d->bad.size(); i++)
{
delete d->bad[i];
}
@ -120,19 +120,19 @@ Process * BadProcesses::operator[](uint32_t index)
Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID)
{
Process *p1 = new SHMProcess(ID.pid,meminfo->versions);
Process *p1 = createSHMProcess(ID.pid,meminfo->versions);
if(p1->isIdentified())
return p1;
else
delete p1;
Process *p2 = new NormalProcess(ID.pid,meminfo->versions);
Process *p2 = createNormalProcess(ID.pid,meminfo->versions);
if(p2->isIdentified())
return p2;
else
delete p2;
#ifdef LINUX_BUILD
Process *p3 = new WineProcess(ID.pid,meminfo->versions);
Process *p3 = createWineProcess(ID.pid,meminfo->versions);
if(p3->isIdentified())
return p3;
else

@ -0,0 +1,31 @@
// vim: sts=4 sta et shiftwidth=4:
#include "dfhack/DFIntegers.h"
#include "dfhack/DFTileTypes.h"
#include "dfhack/DFExport.h"
namespace DFHack {
//set tile class string lookup table (e.g. for printing to user)
#define X(name,comment) #name,
const char * TileClassString[tileclass_count+1] = {
TILECLASS_MACRO
0
};
#undef X
//string lookup table (e.g. for printing to user)
#define X(name,comment) #name,
const char * TileMaterialString[tilematerial_count+1] = {
TILEMATERIAL_MACRO
0
};
#undef X
//string lookup table (e.g. for printing to user)
#define X(name,comment) #name,
const char * TileSpecialString[tilespecial_count+1] = {
TILESPECIAL_MACRO
0
};
#undef X
}

@ -39,6 +39,31 @@ using namespace std;
using namespace DFHack;
/*
I believe this is what they call "the bad kind of clever", but writing out registration functions for each callback just feels *so* wrong...
The output of this macro is something like this...
void RegisterByteBufferCallback(int(*fptr)(int8_t*, uint32_t))
{
alloc_byte_buffer_callback = fptr;
}
*/
#define BUILD(a) a ## BufferCallback
#define REG_MACRO(type_name, type, callback) void BUILD(Register ## type_name) (int (*fptr)(type, uint32_t)) { callback = fptr; }
/*
The output of this macro is something like this...
void UnregisterByteBufferCallback()
{
alloc_byte_buffer_callback = NULL;
}
*/
#define UNREG_MACRO(type_name, callback) void BUILD(Unregister ## type_name) () { callback = NULL; }
#ifdef __cplusplus
extern "C" {
#endif
@ -80,6 +105,114 @@ int (*alloc_vein_buffer_callback)(t_vein*, uint32_t) = NULL;
int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein*, uint32_t) = NULL;
int (*alloc_spattervein_buffer_callback)(t_spattervein*, uint32_t) = NULL;
REG_MACRO(Byte, int8_t*, alloc_byte_buffer_callback)
REG_MACRO(Short, int16_t*, alloc_short_buffer_callback)
REG_MACRO(Int, int32_t*, alloc_int_buffer_callback)
REG_MACRO(UByte, uint8_t*, alloc_ubyte_buffer_callback)
REG_MACRO(UShort, uint16_t*, alloc_ushort_buffer_callback)
REG_MACRO(UInt, uint32_t*, alloc_uint_buffer_callback)
REG_MACRO(Char, char*, alloc_char_buffer_callback)
REG_MACRO(Matgloss, t_matgloss*, alloc_matgloss_buffer_callback)
REG_MACRO(DescriptorColor, t_descriptor_color*, alloc_descriptor_buffer_callback)
REG_MACRO(MatglossOther, t_matglossOther*, alloc_matgloss_other_buffer_callback)
REG_MACRO(Feature, t_feature*, alloc_t_feature_buffer_callback)
REG_MACRO(Hotkey, t_hotkey*, alloc_t_hotkey_buffer_callback)
REG_MACRO(Screen, t_screen*, alloc_t_screen_buffer_callback)
REG_MACRO(CustomWorkshop, t_customWorkshop*, alloc_t_customWorkshop_buffer_callback)
REG_MACRO(Material, t_material*, alloc_t_material_buffer_callback)
UNREG_MACRO(Byte, alloc_byte_buffer_callback)
UNREG_MACRO(Short, alloc_short_buffer_callback)
UNREG_MACRO(Int, alloc_int_buffer_callback)
UNREG_MACRO(UByte, alloc_ubyte_buffer_callback)
UNREG_MACRO(UShort, alloc_ushort_buffer_callback)
UNREG_MACRO(UInt, alloc_uint_buffer_callback)
UNREG_MACRO(Char, alloc_char_buffer_callback)
UNREG_MACRO(Matgloss, alloc_matgloss_buffer_callback)
UNREG_MACRO(DescriptorColor, alloc_descriptor_buffer_callback)
UNREG_MACRO(MatglossOther, alloc_matgloss_other_buffer_callback)
UNREG_MACRO(Feature, alloc_t_feature_buffer_callback)
UNREG_MACRO(Hotkey, alloc_t_hotkey_buffer_callback)
UNREG_MACRO(Screen, alloc_t_screen_buffer_callback)
UNREG_MACRO(CustomWorkshop, alloc_t_customWorkshop_buffer_callback)
UNREG_MACRO(Material, alloc_t_material_buffer_callback)
void RegisterEmptyColorModifierCallback(int (*funcptr)(c_colormodifier*))
{
alloc_empty_colormodifier_callback = funcptr;
}
void RegisterNewColorModifierCallback(int (*funcptr)(c_colormodifier*, const char*, uint32_t))
{
alloc_colormodifier_callback = funcptr;
}
REG_MACRO(ColorModifier, c_colormodifier*, alloc_colormodifier_buffer_callback)
void RegisterEmptyCreatureCasteCallback(int (*funcptr)(c_creaturecaste*))
{
alloc_empty_creaturecaste_callback = funcptr;
}
void UnregisterEmptyColorModifierCallback()
{
alloc_empty_colormodifier_callback = NULL;
}
void UnregisterNewColorModifierCallback()
{
alloc_colormodifier_callback = NULL;
}
void RegisterNewCreatureCasteCallback(int (*funcptr)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t))
{
alloc_creaturecaste_callback = funcptr;
}
REG_MACRO(CreatureCaste, c_creaturecaste*, alloc_creaturecaste_buffer_callback)
UNREG_MACRO(CreatureCaste, alloc_creaturecaste_buffer_callback)
void UnregisterEmptyCreatureCasteCallback()
{
alloc_empty_creaturecaste_callback = NULL;
}
void UnregisterNewCreatureCasteCallback()
{
alloc_creaturecaste_callback = NULL;
}
void RegisterEmptyCreatureTypeCallback(int (*funcptr)(c_creaturetype*))
{
alloc_empty_creaturetype_callback = funcptr;
}
void RegisterNewCreatureTypeCallback(int (*funcptr)(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t))
{
alloc_creaturetype_callback = funcptr;
}
REG_MACRO(CreatureType, c_creaturetype*, alloc_creaturetype_buffer_callback)
UNREG_MACRO(CreatureType, alloc_creaturetype_buffer_callback)
void UnregisterEmptyCreatureTypeCallback()
{
alloc_empty_creaturetype_callback = NULL;
}
void UnregisterNewCreatureTypeCallback()
{
alloc_creaturetype_callback = NULL;
}
REG_MACRO(Vein, t_vein*, alloc_vein_buffer_callback)
REG_MACRO(FrozenLiquidVein, t_frozenliquidvein*, alloc_frozenliquidvein_buffer_callback)
REG_MACRO(SpatterVein, t_spattervein*, alloc_spattervein_buffer_callback)
UNREG_MACRO(Vein, alloc_vein_buffer_callback)
UNREG_MACRO(FrozenLiquidVein, alloc_frozenliquidvein_buffer_callback)
UNREG_MACRO(SpatterVein, alloc_spattervein_buffer_callback)
int DFHack_isWallTerrain(int in)
{
return DFHack::isWallTerrain(in);
@ -143,7 +276,7 @@ int CreatureCasteConvert(t_creaturecaste* src, c_creaturecaste* dest)
((*alloc_creaturecaste_callback)(dest, src->rawname, src->singular, src->plural, src->adjective, src->ColorModifier.size(), src->bodypart.size()));
for(int i = 0; i < dest->colorModifierLength; i++)
for(unsigned int i = 0; i < dest->colorModifierLength; i++)
ColorListConvert(&src->ColorModifier[i], &dest->ColorModifier[i]);
copy(src->bodypart.begin(), src->bodypart.end(), dest->bodypart);
@ -158,7 +291,7 @@ int CreatureTypeConvert(t_creaturetype* src, c_creaturetype* dest)
((*alloc_creaturetype_callback)(dest, src->rawname, src->castes.size(), src->extract.size(), src->tile_character, src->tilecolor.fore, src->tilecolor.back, src->tilecolor.bright));
for(int i = 0; i < dest->castesCount; i++)
for(unsigned int i = 0; i < dest->castesCount; i++)
CreatureCasteConvert(&src->castes[i], &dest->castes[i]);
copy(src->extract.begin(), src->extract.end(), dest->extract);

@ -0,0 +1,96 @@
/*
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 "Internal.h"
#include "MicrosoftSTL.h"
#include "dfhack/DFProcess.h"
#include "dfhack/VersionInfo.h"
#include <string>
using namespace DFHack;
void MicrosoftSTL::init(Process* self)
{
p = self;
OffsetGroup * strGrp = p->getDescriptor()->getGroup("string")->getGroup("MSVC");
STLSTR_buf_off = strGrp->getOffset("buffer");
STLSTR_size_off = strGrp->getOffset("size");
STLSTR_cap_off = strGrp->getOffset("capacity");
}
size_t MicrosoftSTL::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{
uint32_t start_offset = offset + STLSTR_buf_off;
size_t length = p->readDWord(offset + STLSTR_size_off);
size_t capacity = p->readDWord(offset + STLSTR_cap_off);
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
// read data from inside the string structure
if(capacity < 16)
{
p->read(start_offset, read_real , (uint8_t *)buffer);
}
else // read data from what the offset + 4 dword points to
{
start_offset = p->readDWord(start_offset);// dereference the start offset
p->read(start_offset, read_real, (uint8_t *)buffer);
}
buffer[read_real] = 0;
return read_real;
}
const string MicrosoftSTL::readSTLString (uint32_t offset)
{
uint32_t start_offset = offset + STLSTR_buf_off;
size_t length = p->readDWord(offset + STLSTR_size_off);
size_t capacity = p->readDWord(offset + STLSTR_cap_off);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
p->read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = p->readDWord(start_offset);// dereference the start offset
p->read(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}
string MicrosoftSTL::readClassName (uint32_t vptr)
{
int rtti = p->readDWord(vptr - 0x4);
int typeinfo = p->readDWord(rtti + 0xC);
string raw = p->readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 2);// trim @@ from end
return raw;
}

@ -127,11 +127,11 @@ namespace DFHack
*/
namespace DFHack
{
typedef pair <bool, uint32_t> nullableUint32;
typedef pair <INVAL_TYPE, uint32_t> nullableUint32;
typedef map <string, nullableUint32 >::iterator uint32_Iter;
typedef pair <bool, int32_t> nullableInt32;
typedef pair <INVAL_TYPE, int32_t> nullableInt32;
typedef map <string, nullableInt32 >::iterator int32_Iter;
typedef pair <bool, string> nullableString;
typedef pair <INVAL_TYPE, string> nullableString;
typedef map <string, nullableString >::iterator strings_Iter;
typedef map <string, OffsetGroup *>::iterator groups_Iter;
class OffsetGroupPrivate
@ -149,73 +149,126 @@ namespace DFHack
void OffsetGroup::createOffset(const string & key)
{
OGd->offsets[key] = nullableInt32(false, 0);
OGd->offsets[key] = nullableInt32(NOT_SET, 0);
}
void OffsetGroup::createAddress(const string & key)
{
OGd->addresses[key] = nullableUint32(false, 0);
OGd->addresses[key] = nullableUint32(NOT_SET, 0);
}
void OffsetGroup::createHexValue(const string & key)
{
OGd->hexvals[key] = nullableUint32(false, 0);
OGd->hexvals[key] = nullableUint32(NOT_SET, 0);
}
void OffsetGroup::createString(const string & key)
{
OGd->strings[key] = nullableString(false, std::string());
OGd->strings[key] = nullableString(NOT_SET, std::string());
}
void OffsetGroup::setOffset (const string & key, const string & value)
void OffsetGroup::setOffset (const string & key, const string & value, const INVAL_TYPE inval)
{
int32_Iter it = OGd->offsets.find(key);
if(it != OGd->offsets.end())
{
int32_t offset = strtol(value.c_str(), NULL, 16);
(*it).second.second = offset;
(*it).second.first = true;
if(inval != NOT_SET)
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("offset", getFullName() + key);
}
void OffsetGroup::setOffsetValidity (const string & key, const INVAL_TYPE inval)
{
if(inval != NOT_SET)
{
int32_Iter it = OGd->offsets.find(key);
if(it != OGd->offsets.end())
{
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("offset", getFullName() + key);
}
}
void OffsetGroup::setAddress (const string & key, const string & value)
void OffsetGroup::setAddress (const string & key, const string & value, const INVAL_TYPE inval)
{
uint32_Iter it = OGd->addresses.find(key);
if(it != OGd->addresses.end())
{
int32_t address = strtol(value.c_str(), NULL, 16);
(*it).second.second = address;
(*it).second.first = true;
if(inval != NOT_SET)
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("address", getFullName() + key);
}
void OffsetGroup::setAddressValidity (const string & key, const INVAL_TYPE inval)
{
if(inval != NOT_SET)
{
uint32_Iter it = OGd->addresses.find(key);
if(it != OGd->addresses.end())
{
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("address", getFullName() + key);
}
}
void OffsetGroup::setHexValue (const string & key, const string & value)
void OffsetGroup::setHexValue (const string & key, const string & value, const INVAL_TYPE inval)
{
uint32_Iter it = OGd->hexvals.find(key);
if(it != OGd->hexvals.end())
{
(*it).second.second = strtol(value.c_str(), NULL, 16);
(*it).second.first = true;
if(inval != NOT_SET)
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key);
}
void OffsetGroup::setHexValueValidity (const string & key, const INVAL_TYPE inval)
{
if(inval != NOT_SET)
{
uint32_Iter it = OGd->hexvals.find(key);
if(it != OGd->hexvals.end())
{
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key);
}
}
void OffsetGroup::setString (const string & key, const string & value)
void OffsetGroup::setString (const string & key, const string & value, const INVAL_TYPE inval)
{
strings_Iter it = OGd->strings.find(key);
if(it != OGd->strings.end())
{
(*it).second.second = value;
(*it).second.first = true;
if(inval != NOT_SET)
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("string", getFullName() + key);
}
void OffsetGroup::setStringValidity (const string & key, const INVAL_TYPE inval)
{
if(inval != NOT_SET)
{
strings_Iter it = OGd->strings.find(key);
if(it != OGd->strings.end())
{
(*it).second.first = inval;
}
else throw Error::MissingMemoryDefinition("string", getFullName() + key);
}
}
// Get named address
uint32_t OffsetGroup::getAddress (const string & key)
@ -224,8 +277,10 @@ uint32_t OffsetGroup::getAddress (const string & key)
if(iter != OGd->addresses.end())
{
if((*iter).second.first)
if((*iter).second.first == IS_VALID)
return (*iter).second.second;
if((*iter).second.first == IS_INVALID)
throw Error::InvalidMemoryDefinition("address", getFullName() + key);
throw Error::UnsetMemoryDefinition("address", getFullName() + key);
}
throw Error::MissingMemoryDefinition("address", getFullName() + key);
@ -238,8 +293,10 @@ int32_t OffsetGroup::getOffset (const string & key)
int32_Iter iter = OGd->offsets.find(key);
if(iter != OGd->offsets.end())
{
if((*iter).second.first)
if((*iter).second.first == IS_VALID)
return (*iter).second.second;
if((*iter).second.first == IS_INVALID)
throw Error::InvalidMemoryDefinition("offset", getFullName() + key);
throw Error::UnsetMemoryDefinition("offset", getFullName() + key);
}
throw Error::MissingMemoryDefinition("offset", getFullName() + key);
@ -252,8 +309,10 @@ uint32_t OffsetGroup::getHexValue (const string & key)
uint32_Iter iter = OGd->hexvals.find(key);
if(iter != OGd->hexvals.end())
{
if((*iter).second.first)
if((*iter).second.first == IS_VALID)
return (*iter).second.second;
if((*iter).second.first == IS_INVALID)
throw Error::InvalidMemoryDefinition("hexvalue", getFullName() + key);
throw Error::UnsetMemoryDefinition("hexvalue", getFullName() + key);
}
throw Error::MissingMemoryDefinition("hexvalue", getFullName() + key);
@ -265,8 +324,10 @@ std::string OffsetGroup::getString (const string &key)
strings_Iter iter = OGd->strings.find(key);
if(iter != OGd->strings.end())
{
if((*iter).second.first)
if((*iter).second.first == IS_VALID)
return (*iter).second.second;
if((*iter).second.first == IS_INVALID)
throw Error::InvalidMemoryDefinition("string", getFullName() + key);
throw Error::UnsetMemoryDefinition("string", getFullName() + key);
}
throw Error::MissingMemoryDefinition("string", getFullName() + key);
@ -361,6 +422,8 @@ std::string OffsetGroup::PrintOffsets(int indentation)
if((*iter).second.first)
ss << " value=\"" << hex << "0x" << (*iter).second.second << "\"";
ss << " />";
if((*iter).second.first == IS_INVALID)
ss << " INVALID!";
if(!(*iter).second.first)
ss << " MISSING!";
ss << endl;
@ -372,6 +435,8 @@ std::string OffsetGroup::PrintOffsets(int indentation)
if((*iter2).second.first)
ss << " value=\"" << hex << "0x" << (*iter2).second.second << "\"";
ss << " />";
if((*iter2).second.first == IS_INVALID)
ss << " INVALID!";
if(!(*iter2).second.first)
ss << " MISSING!";
ss << endl;
@ -382,6 +447,8 @@ std::string OffsetGroup::PrintOffsets(int indentation)
if((*iter).second.first)
ss << " value=\"" << hex << "0x" << (*iter).second.second << "\"";
ss << " />";
if((*iter).second.first == IS_INVALID)
ss << " INVALID!";
if(!(*iter).second.first)
ss << " MISSING!";
ss << endl;
@ -393,6 +460,8 @@ std::string OffsetGroup::PrintOffsets(int indentation)
if((*iter3).second.first)
ss << " value=\"" << (*iter3).second.second << "\"";
ss << " />";
if((*iter3).second.first == IS_INVALID)
ss << " INVALID!";
if(!(*iter3).second.first)
ss << " MISSING!";
ss << endl;
@ -409,6 +478,42 @@ std::string OffsetGroup::PrintOffsets(int indentation)
return ss.str();
}
// the big ugly method behind the curtain...
void OffsetGroup::setInvalid(INVAL_TYPE invalidity)
{
if(invalidity == NOT_SET)
return;
uint32_Iter iter;
for(iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++)
{
if((*iter).second.first)
(*iter).second.first = invalidity;
}
int32_Iter iter2;
for(iter2 = OGd->offsets.begin(); iter2 != OGd->offsets.end(); iter2++)
{
if((*iter2).second.first)
(*iter2).second.first = invalidity;
}
for(iter = OGd->hexvals.begin(); iter != OGd->hexvals.end(); iter++)
{
if((*iter).second.first)
(*iter).second.first = invalidity;
}
strings_Iter iter3;
for(iter3 = OGd->strings.begin(); iter3 != OGd->strings.end(); iter3++)
{
if((*iter3).second.first)
(*iter3).second.first = invalidity;
}
groups_Iter iter4;
for(iter4 = OGd->groups.begin(); iter4 != OGd->groups.end(); iter4++)
{
(*iter4).second->setInvalid(invalidity);
}
}
/*
* Private data
*/
@ -440,7 +545,7 @@ namespace DFHack
Process * p; // the process this belongs to
string version;
VersionInfo::OSType OS;
OSType OS;
std::string md5;
uint32_t PE_timestamp;
};
@ -602,7 +707,7 @@ void VersionInfo::setOS(OSType os)
}
VersionInfo::OSType VersionInfo::getOS() const
OSType VersionInfo::getOS() const
{
return d->OS;
}

@ -31,6 +31,65 @@ distribution.
using namespace DFHack;
template<class _T1, class _T2, class _T3>
struct triple
{
typedef _T1 first_type;
typedef _T2 second_type;
typedef _T3 third_type;
_T1 first;
_T2 second;
_T3 third;
triple() : first(), second(), third() { }
triple(const _T1& __a, const _T2& __b, const _T3& __c) : first(__a), second(__b), third(__c) { }
template<class _U1, class _U2, class _U3>
triple(const triple<_U1, _U2, _U3>& __p) : first(__p.first), second(__p.second), third(__p.third) { }
};
template<class _T1, class _T2, class _T3>
inline bool operator==(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return __x.first == __y.first && __x.second == __y.second && __x.third == __y.third;
}
template<class _T1, class _T2, class _T3>
inline bool operator<(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return
__x.first < __y.first ||
(!(__y.first < __x.first) && __x.second < __y.second) ||
(!(__y.first < __x.first) && !(__x.second < __y.second) && (__x.third < __y.third));
}
template<class _T1, class _T2, class _T3>
inline bool operator!=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return !(__x == __y);
}
template<class _T1, class _T2, class _T3>
inline bool operator>(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return __y < __x;
}
template<class _T1, class _T2, class _T3>
inline bool operator<=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return !(__y < __x);
}
template<class _T1, class _T2, class _T3>
inline bool operator>=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2, _T3>& __y)
{
return !(__x < __y);
}
VersionInfoFactory::~VersionInfoFactory()
{
// for each stored version, delete
@ -95,35 +154,54 @@ void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem)
}
}
// FIXME: this is ripe for replacement with a more generic approach
struct breadcrumb
{
TiXmlElement * first;
OffsetGroup * second;
};
void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target, bool initial)
{
// we parse the groups iteratively instead of recursively
// breadcrubs acts like a makeshift stack
// first pair entry stores the current element of that level
// second pair entry the group object from OffsetGroup
typedef pair < TiXmlElement *, OffsetGroup * > groupPair;
vector< groupPair > breadcrumbs;
typedef triple< TiXmlElement *, OffsetGroup *, INVAL_TYPE> groupTriple;
vector< groupTriple > breadcrumbs;
{
TiXmlElement* pEntry;
// we get the <Offsets>, look at the children
pEntry = parent->FirstChildElement();
const char *cstr_invalid = parent->Attribute("valid");
INVAL_TYPE parent_inval = NOT_SET;
if(cstr_invalid)
{
if(strcmp(cstr_invalid,"false") == 0)
parent_inval = IS_INVALID;
else if(strcmp(cstr_invalid,"true") == 0)
parent_inval = IS_VALID;
}
OffsetGroup * currentGroup = reinterpret_cast<OffsetGroup *> (target);
currentGroup->setInvalid(parent_inval);
// we end here if there are no child tags.
if(!pEntry)
return;
OffsetGroup * currentGroup = reinterpret_cast<OffsetGroup *> (target);
breadcrumbs.push_back(groupPair(pEntry,currentGroup));
breadcrumbs.push_back(groupTriple(pEntry,currentGroup, parent_inval));
}
// work variables
OffsetGroup * currentGroup = 0;
TiXmlElement * currentElem = 0;
INVAL_TYPE parent_inval = NOT_SET;
//cerr << "<Offsets>"<< endl;
while(1)
{
// get current work variables
currentElem = breadcrumbs.back().first;
currentGroup = breadcrumbs.back().second;
parent_inval = breadcrumbs.back().third;
// we reached the end of the current group?
if(!currentElem)
@ -144,7 +222,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target
if(!currentGroup)
{
groupPair & gp = breadcrumbs.back();
groupTriple & gp = breadcrumbs.back();
gp.first = gp.first->NextSiblingElement();
continue;
}
@ -152,7 +230,7 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target
// skip non-elements
if (currentElem->Type() != TiXmlNode::ELEMENT)
{
groupPair & gp = breadcrumbs.back();
groupTriple & gp = breadcrumbs.back();
gp.first = gp.first->NextSiblingElement();
continue;
}
@ -169,18 +247,27 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target
// evaluate elements
const char *cstr_value = currentElem->Attribute("value");
const char *cstr_invalid = currentElem->Attribute("valid");
INVAL_TYPE child_inval = parent_inval;
if(cstr_invalid)
{
if(strcmp(cstr_invalid,"false") == 0)
child_inval = IS_INVALID;
else if(strcmp(cstr_invalid,"true") == 0)
child_inval = IS_VALID;
}
if(type == "group")
{
// FIXME: possibly use setGroup always, with the initial flag as parameter?
// create or get group
OffsetGroup * og;
if(initial)
og = currentGroup->createGroup(cstr_name);
else
og = currentGroup->getGroup(cstr_name);
//cerr << "<group name=\"" << cstr_name << "\">" << endl;
// advance this level to the next element
groupPair & gp = breadcrumbs.back();
groupTriple & gp = breadcrumbs.back();
gp.first = currentElem->NextSiblingElement();
if(!og)
@ -189,73 +276,82 @@ void VersionInfoFactory::ParseOffsets(TiXmlElement * parent, VersionInfo* target
throw Error::MissingMemoryDefinition("group", fullname);
}
// add a new level that will be processed next
breadcrumbs.push_back(groupPair(currentElem->FirstChildElement(), og));
// add a new level that will be processed in the next step
breadcrumbs.push_back(groupTriple(currentElem->FirstChildElement(), og, child_inval));
og->setInvalid(child_inval);
continue;
}
else if(type == "address")
{
if(child_inval == NOT_SET)
child_inval = IS_VALID;
if(initial)
{
currentGroup->createAddress(cstr_name);
}
else if(cstr_value)
{
currentGroup->setAddress(cstr_name, cstr_value);
currentGroup->setAddress(cstr_name, cstr_value, child_inval);
}
else
{
// ERROR, missing attribute
currentGroup->setAddressValidity(cstr_name, child_inval);
}
}
else if(type == "offset")
{
if(child_inval == NOT_SET)
child_inval = IS_VALID;
if(initial)
{
currentGroup->createOffset(cstr_name);
}
else if(cstr_value)
{
currentGroup->setOffset(cstr_name, cstr_value);
currentGroup->setOffset(cstr_name, cstr_value, child_inval);
}
else
{
// ERROR, missing attribute
currentGroup->setOffsetValidity(cstr_name, child_inval);
}
}
else if(type == "string")
{
if(child_inval == NOT_SET)
child_inval = IS_VALID;
if(initial)
{
currentGroup->createString(cstr_name);
}
else if(cstr_value)
{
currentGroup->setString(cstr_name, cstr_value);
currentGroup->setString(cstr_name, cstr_value, child_inval);
}
else
{
// ERROR, missing attribute
currentGroup->setStringValidity(cstr_name, child_inval);
}
}
else if(type == "hexvalue")
{
if(child_inval == NOT_SET)
child_inval = IS_VALID;
if(initial)
{
currentGroup->createHexValue(cstr_name);
}
else if(cstr_value)
{
currentGroup->setHexValue(cstr_name, cstr_value);
currentGroup->setHexValue(cstr_name, cstr_value, child_inval);
}
else
{
// ERROR, missing attribute
currentGroup->setHexValueValidity(cstr_name, child_inval);
}
}
// advance to next element
groupPair & gp = breadcrumbs.back();
groupTriple & gp = breadcrumbs.back();
gp.first = currentElem->NextSiblingElement();
continue;
}
@ -272,7 +368,7 @@ void VersionInfoFactory::ParseBase (TiXmlElement* entry, VersionInfo* mem)
throw Error::MemoryXmlBadAttribute("name");
mem->setVersion(cstr_version);
mem->setOS(VersionInfo::OS_BAD);
mem->setOS(OS_BAD);
// process additional entries
pElement = entry->FirstChildElement()->ToElement();
@ -590,7 +686,6 @@ bool VersionInfoFactory::loadFile(string path_to_xml)
if(name)
{
string str_name = name;
VersionInfo *base = new VersionInfo();
mem = new VersionInfo();
ParseBase( pMemInfo , mem );
knownVersions[str_name] = v_descr (pMemInfo, mem);

Binary file not shown.

@ -25,6 +25,8 @@ distribution.
#ifndef DFHACK_C_API
#define DFHACK_C_API
#include "dfhack/DFPragma.h"
#include <cstdio>
#include <string>
#include <vector>

@ -32,6 +32,11 @@ distribution.
#include "dfhack/modules/Position.h"
#include "dfhack/DFTileTypes.h"
#define HBUILD(a) a ## BufferCallback
#define HREG_MACRO(type_name, type) DFHACK_EXPORT void HBUILD(Register ## type_name) (int (*funcptr)(type, uint32_t));
#define HUNREG_MACRO(type_name) DFHACK_EXPORT void HBUILD(Unregister ## type_name) ();
#ifdef __cplusplus
extern "C" {
#endif
@ -54,6 +59,41 @@ DFHACK_EXPORT extern int (*alloc_t_feature_buffer_callback)(t_feature*, uint32_t
DFHACK_EXPORT extern int (*alloc_t_hotkey_buffer_callback)(t_hotkey*, uint32_t);
DFHACK_EXPORT extern int (*alloc_t_screen_buffer_callback)(t_screen*, uint32_t);
DFHACK_EXPORT void RegisterByteBufferCallback(int (*funcptr)(int8_t*, uint32_t));
DFHACK_EXPORT void RegisterShortBufferCallback(int (*funcptr)(int16_t*, uint32_t));
DFHACK_EXPORT void RegisterIntBufferCallback(int (*funcptr)(int32_t*, uint32_t));
DFHACK_EXPORT void RegisterUByteBufferCallback(int (*funcptr)(uint8_t*, uint32_t));
DFHACK_EXPORT void RegisterUShortBufferCallback(int (*funcptr)(uint16_t*, uint32_t));
DFHACK_EXPORT void RegisterUIntBufferCallback(int (*funcptr)(uint32_t*, uint32_t));
DFHACK_EXPORT void RegisterCharBufferCallback(int (*funcptr)(char*, uint32_t));
DFHACK_EXPORT void RegisterMatglossBufferCallback(int (*funcptr)(t_matgloss*, uint32_t));
DFHACK_EXPORT void RegisterDescriptorColorBufferCallback(int (*funcptr)(t_descriptor_color*, uint32_t));
DFHACK_EXPORT void RegisterMatglossOtherBufferCallback(int (*funcptr)(t_matglossOther*, uint32_t));
DFHACK_EXPORT void RegisterFeatureBufferCallback(int (*funcptr)(t_feature*, uint32_t));
DFHACK_EXPORT void RegisterHotkeyBufferCallback(int (*funcptr)(t_hotkey*, uint32_t));
DFHACK_EXPORT void RegisterScreenBufferCallback(int (*funcptr)(t_screen*, uint32_t));
HUNREG_MACRO(Byte)
HUNREG_MACRO(Short)
HUNREG_MACRO(Int)
HUNREG_MACRO(UByte)
HUNREG_MACRO(UShort)
HUNREG_MACRO(UInt)
HUNREG_MACRO(Char)
HUNREG_MACRO(Matgloss)
HUNREG_MACRO(DescriptorColor)
HUNREG_MACRO(MatglossOther)
HUNREG_MACRO(Feature)
HUNREG_MACRO(Hotkey)
HUNREG_MACRO(Screen)
struct t_customWorkshop
{
uint32_t index;
@ -61,9 +101,14 @@ struct t_customWorkshop
};
DFHACK_EXPORT extern int (*alloc_t_customWorkshop_buffer_callback)(t_customWorkshop*, uint32_t);
DFHACK_EXPORT extern int (*alloc_t_material_buffer_callback)(t_material*, uint32_t);
DFHACK_EXPORT void RegisterCustomWorkshopBufferCallback(int (*funcptr)(t_customWorkshop*, uint32_t));
DFHACK_EXPORT void RegisterMaterialBufferCallback(int (*funcptr)(t_material*, uint32_t));
HUNREG_MACRO(CustomWorkshop)
HUNREG_MACRO(Material)
struct c_colormodifier
{
char part[128];
@ -75,6 +120,14 @@ DFHACK_EXPORT extern int (*alloc_empty_colormodifier_callback)(c_colormodifier*)
DFHACK_EXPORT extern int (*alloc_colormodifier_callback)(c_colormodifier*, const char*, uint32_t);
DFHACK_EXPORT extern int (*alloc_colormodifier_buffer_callback)(c_colormodifier*, uint32_t);
DFHACK_EXPORT void RegisterEmptyColorModifierCallback(int (*funcptr)(c_colormodifier*));
DFHACK_EXPORT void RegisterNewColorModifierCallback(int (*funcptr)(c_colormodifier*, const char*, uint32_t));
DFHACK_EXPORT void RegisterColorModifierBufferCallback(int (*funcptr)(c_colormodifier*, uint32_t));
DFHACK_EXPORT void UnregisterEmptyColorModifierCallback();
DFHACK_EXPORT void UnregisterNewColorModifierCallback();
HUNREG_MACRO(ColorModifier)
struct c_creaturecaste
{
char rawname[128];
@ -93,6 +146,14 @@ DFHACK_EXPORT extern int (*alloc_empty_creaturecaste_callback)(c_creaturecaste*)
DFHACK_EXPORT extern int (*alloc_creaturecaste_callback)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t);
DFHACK_EXPORT extern int (*alloc_creaturecaste_buffer_callback)(c_creaturecaste*, uint32_t);
DFHACK_EXPORT void RegisterEmptyCreatureCasteCallback(int (*funcptr)(c_creaturecaste*));
DFHACK_EXPORT void RegisterNewCreatureCasteCallback(int (*funcptr)(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t));
DFHACK_EXPORT void RegisterCreatureCasteBufferCallback(int (*funcptr)(c_creaturecaste*, uint32_t));
DFHACK_EXPORT void UnregisterEmptyCreatureCasteCallback();
DFHACK_EXPORT void UnregisterNewCreatureCasteCallback();
HUNREG_MACRO(CreatureCaste)
struct c_creaturetype
{
char rawname[128];
@ -121,14 +182,30 @@ DFHACK_EXPORT extern int (*alloc_vein_buffer_callback)(t_vein*, uint32_t);
DFHACK_EXPORT extern int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein*, uint32_t);
DFHACK_EXPORT extern int (*alloc_spattervein_buffer_callback)(t_spattervein*, uint32_t);
DFHACK_EXPORT extern int DFHack_isWallTerrain(int in);
DFHACK_EXPORT extern int DFHack_isFloorTerrain(int in);
DFHACK_EXPORT extern int DFHack_isRampTerrain(int in);
DFHACK_EXPORT extern int DFHack_isStairTerrain(int in);
DFHACK_EXPORT extern int DFHack_isOpenTerrain(int in);
DFHACK_EXPORT extern int DFHack_getVegetationType(int in);
DFHACK_EXPORT void RegisterEmptyCreatureTypeCallback(int (*funcptr)(c_creaturetype*));
DFHACK_EXPORT void RegisterNewCreatureTypeCallback(int (*funcptr)(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t));
DFHACK_EXPORT void RegisterCreatureTypeBufferCallback(int (*funcptr)(c_creaturetype*, uint32_t));
DFHACK_EXPORT void RegisterVeinBufferCallback(int (*funcptr)(t_vein*, uint32_t));
DFHACK_EXPORT void RegisterFrozenLiquidVeinBufferCallback(int (*funcptr)(t_frozenliquidvein*, uint32_t));
DFHACK_EXPORT void RegisterSpatterVeinBufferCallback(int (*funcptr)(t_spattervein*, uint32_t));
DFHACK_EXPORT void UnregisterEmptyCreatureTypeCallback();
DFHACK_EXPORT void UnregisterNewCreatureTypeCallback();
HUNREG_MACRO(CreatureType)
HUNREG_MACRO(Vein)
HUNREG_MACRO(FrozenLiquidVein)
HUNREG_MACRO(SpatterVein)
DFHACK_EXPORT int DFHack_isWallTerrain(int in);
DFHACK_EXPORT int DFHack_isFloorTerrain(int in);
DFHACK_EXPORT int DFHack_isRampTerrain(int in);
DFHACK_EXPORT int DFHack_isStairTerrain(int in);
DFHACK_EXPORT int DFHack_isOpenTerrain(int in);
DFHACK_EXPORT int DFHack_getVegetationType(int in);
DFHACK_EXPORT extern int DFHack_getTileType(int index, TileRow* tPtr);
DFHACK_EXPORT int DFHack_getTileType(int index, TileRow* tPtr);
#ifdef __cplusplus
}

@ -45,6 +45,9 @@ DFHACK_EXPORT int32_t Creatures_ReadCreatureInBox(DFHackObject* cPtr, const int3
DFHACK_EXPORT int Creatures_ReadCreature(DFHackObject* cPtr, const int32_t index, t_creature* furball);
DFHACK_EXPORT t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball);
DFHACK_EXPORT uint32_t* Creatures_ReadInventoryIdx(DFHackObject* cPtr, const uint32_t index);
DFHACK_EXPORT uint32_t* Creatures_ReadInventoryPtr(DFHackObject* cPtr, const uint32_t index);
DFHACK_EXPORT uint32_t Creatures_GetDwarfRaceIndex(DFHackObject* cPtr);
DFHACK_EXPORT int32_t Creatures_GetDwarfCivId(DFHackObject* cPtr);

@ -37,6 +37,7 @@ DFHACK_EXPORT int Gui_Start(DFHackObject* gui);
DFHACK_EXPORT int Gui_Finish(DFHackObject* gui);
DFHACK_EXPORT int Gui_ReadPauseState(DFHackObject* gui);
DFHACK_EXPORT int Gui_SetPauseState(DFHackObject* gui, int8_t paused);
DFHACK_EXPORT int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen);
DFHACK_EXPORT int Gui_ReadMenuState(DFHackObject* gui, uint32_t* menuState);

@ -36,6 +36,8 @@ extern "C" {
DFHACK_EXPORT int Maps_Start(DFHackObject* maps);
DFHACK_EXPORT int Maps_Finish(DFHackObject* maps);
DFHACK_EXPORT uint16_t* Maps_ReadGeology(DFHackObject* maps);
DFHACK_EXPORT t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps);
DFHACK_EXPORT void Maps_getSize(DFHackObject* maps, uint32_t* x, uint32_t* y, uint32_t* z);

@ -26,6 +26,7 @@ distribution.
#define ERROR_H_INCLUDED
#include "DFExport.h"
#include "DFPragma.h"
#include <string>
#include <sstream>
#include <exception>
@ -39,6 +40,7 @@ namespace DFHack
* the whole array of DFHack exceptions from the rest
*/
class DFHACK_EXPORT All : public std::exception{};
class DFHACK_EXPORT AllMemdef : public All{};
class DFHACK_EXPORT NoProcess : public All
{
public:
@ -80,7 +82,7 @@ namespace DFHack
};
// a call to DFHack::mem_info::get* failed
class DFHACK_EXPORT MissingMemoryDefinition : public All
class DFHACK_EXPORT MissingMemoryDefinition : public AllMemdef
{
public:
MissingMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key)
@ -113,7 +115,7 @@ namespace DFHack
};
// a call to DFHack::mem_info::get* failed
class DFHACK_EXPORT UnsetMemoryDefinition : public All
class DFHACK_EXPORT UnsetMemoryDefinition : public AllMemdef
{
public:
UnsetMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key)
@ -145,7 +147,41 @@ namespace DFHack
}
};
// Syntax errors and whatnot, the xml cant be read
// a call to DFHack::mem_info::get* failed
class DFHACK_EXPORT InvalidMemoryDefinition : public AllMemdef
{
public:
InvalidMemoryDefinition(const char* _type, const std::string _key) : type(_type), key(_key)
{
std::stringstream s;
s << "memory object is INVALID: type " << type << " key " << key;
full = s.str();
}
// Used by functios using integer keys, such as getTrait
InvalidMemoryDefinition(const char* _type, uint32_t _key) : type(_type)
{
std::stringstream s1;
s1 << _key;
key = s1.str();
std::stringstream s;
s << "memory object is INVALID: type " << type << " key " << key;
full = s.str();
}
virtual ~InvalidMemoryDefinition() throw(){};
std::string full;
const std::string type;
std::string key;
virtual const char* what() const throw()
{
return full.c_str();
}
};
// Syntax errors and whatnot, the xml can't be read
class DFHACK_EXPORT MemoryXmlParse : public All
{
public:
@ -156,14 +192,12 @@ namespace DFHack
s << "error " << id << ": " << desc << ", at row " << row << " col " << col;
full = s.str();
}
std::string full;
const std::string desc;
const int id;
const int row;
const int col;
virtual ~MemoryXmlParse() throw(){};
virtual const char* what() const throw()

@ -7,8 +7,18 @@
#ifdef _MSC_VER
// don't spew nonsense
#pragma warning( disable: 4251 )
// don't display bogus 'deprecation' and 'unsafe' warnings
// don't display bogus 'deprecation' and 'unsafe' warnings.
// See the idiocy: http://msdn.microsoft.com/en-us/magazine/cc163794.aspx
#define _CRT_SECURE_NO_DEPRECATE
#define _SCL_SECURE_NO_DEPRECATE
#pragma warning( disable: 4996 )
// Let me demonstrate:
/**
* [peterix@peterix dfhack]$ man wcscpy_s
* No manual entry for wcscpy_s
*
* Proprietary extensions.
*/
// disable stupid
#pragma warning( disable: 4800 )
// disable more stupid

@ -72,6 +72,7 @@ namespace DFHack
if (address >= start && address <= end) return true;
return false;
}
bool valid;
uint8_t * buffer;
};
@ -98,33 +99,33 @@ namespace DFHack
virtual bool forceresume() = 0;
/// read a 8-byte integer
virtual uint64_t readQuad(const uint32_t address) = 0;
uint64_t readQuad(const uint32_t address) { uint64_t result; readQuad(address, result); return result; }
/// read a 8-byte integer
virtual void readQuad(const uint32_t address, uint64_t & value) = 0;
/// write a 8-byte integer
virtual void writeQuad(const uint32_t address, const uint64_t value) = 0;
/// read a 4-byte integer
virtual uint32_t readDWord(const uint32_t address) = 0;
uint32_t readDWord(const uint32_t address) { uint32_t result; readDWord(address, result); return result; }
/// read a 4-byte integer
virtual void readDWord(const uint32_t address, uint32_t & value) = 0;
/// write a 4-byte integer
virtual void writeDWord(const uint32_t address, const uint32_t value) = 0;
/// read a float
virtual float readFloat(const uint32_t address) = 0;
float readFloat(const uint32_t address) { float result; readFloat(address, result); return result; }
/// write a float
virtual void readFloat(const uint32_t address, float & value) = 0;
/// read a 2-byte integer
virtual uint16_t readWord(const uint32_t address) = 0;
uint16_t readWord(const uint32_t address) { uint16_t result; readWord(address, result); return result; }
/// read a 2-byte integer
virtual void readWord(const uint32_t address, uint16_t & value) = 0;
/// write a 2-byte integer
virtual void writeWord(const uint32_t address, const uint16_t value) = 0;
/// read a byte
virtual uint8_t readByte(const uint32_t address) = 0;
uint8_t readByte(const uint32_t address) { uint8_t result; readByte(address, result); return result; }
/// read a byte
virtual void readByte(const uint32_t address, uint8_t & value) = 0;
/// write a byte
@ -163,6 +164,8 @@ namespace DFHack
virtual VersionInfo *getDescriptor() = 0;
/// get the DF Process ID
virtual int getPID() = 0;
/// get the DF Process FilePath
virtual std::string getPath() = 0;
/// get module index by name and version. bool 1 = error
virtual bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) = 0;
/// get the SHM start if available
@ -171,200 +174,5 @@ namespace DFHack
virtual bool SetAndWait (uint32_t state) = 0;
};
////////////////////////////////////////////////////////////////////////////
// Compiler appeasement area. Not worth a look really... //
////////////////////////////////////////////////////////////////////////////
class DFHACK_EXPORT NormalProcess : virtual public Process
{
friend class ProcessEnumerator;
class Private;
private:
Private * const d;
public:
NormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
~NormalProcess();
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
uint64_t readQuad(const uint32_t address);
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
uint32_t readDWord(const uint32_t address);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
float readFloat(const uint32_t address);
void readFloat(const uint32_t address, float & value);
uint16_t readWord(const uint32_t address);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
uint8_t readByte(const uint32_t address);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::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){};
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
VersionInfo *getDescriptor();
int getPID();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { OUTPUT=0; return false;};
// get the SHM start if available
char * getSHMStart (void){return 0;};
// set a SHM command and wait for a response
bool SetAndWait (uint32_t state){return false;};
};
class DFHACK_EXPORT SHMProcess : virtual public Process
{
friend class ProcessEnumerator;
class Private;
private:
Private * const d;
public:
SHMProcess(uint32_t PID, std::vector <VersionInfo *> & known_versions);
~SHMProcess();
// Set up stuff so we can read memory
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
uint64_t readQuad(const uint32_t address);
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
uint32_t readDWord(const uint32_t address);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
float readFloat(const uint32_t address);
void readFloat(const uint32_t address, float & value);
uint16_t readWord(const uint32_t address);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
uint8_t readByte(const uint32_t address);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::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);
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
VersionInfo *getDescriptor();
int getPID();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT);
// get the SHM start if available
char * getSHMStart (void);
bool SetAndWait (uint32_t state);
};
#ifdef LINUX_BUILD
class DFHACK_EXPORT WineProcess : virtual public Process
{
friend class ProcessEnumerator;
class Private;
private:
Private * const d;
public:
WineProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
~WineProcess();
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
uint64_t readQuad(const uint32_t address);
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
uint32_t readDWord(const uint32_t address);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
float readFloat(const uint32_t address);
void readFloat(const uint32_t address, float & value);
uint16_t readWord(const uint32_t address);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
uint8_t readByte(const uint32_t address);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::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){};
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
VersionInfo *getDescriptor();
int getPID();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {OUTPUT=0; return false;};
// get the SHM start if available
char * getSHMStart (void){return 0;};
bool SetAndWait (uint32_t state){return false;};
};
#endif
}
#endif

File diff suppressed because it is too large Load Diff

@ -41,6 +41,13 @@ namespace DFHack
class VersionInfoPrivate;
class OffsetGroupPrivate;
enum INVAL_TYPE
{
NOT_SET,
IS_INVALID,
IS_VALID
};
/*
* Offset Group
*/
@ -68,31 +75,36 @@ namespace DFHack
std::string getString (const std::string & key);
OffsetGroup * getGroup ( const std::string & name );
void setOffset (const std::string & key, const std::string & value);
void setAddress (const std::string & key, const std::string & value);
void setHexValue (const std::string & key, const std::string & value);
void setString (const std::string & key, const std::string & value);
void setOffset (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);
void setOffsetValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID);
void setAddress (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);
void setAddressValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID);
void setHexValue (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);
void setHexValueValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID);
void setString (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);
void setStringValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID);
std::string PrintOffsets(int indentation);
std::string getName();
std::string getFullName();
OffsetGroup * getParent();
void setInvalid(INVAL_TYPE arg1);
};
/*
* Version Info
*/
enum OSType
{
OS_WINDOWS,
OS_LINUX,
OS_APPLE,
OS_BAD
};
class DFHACK_EXPORT VersionInfo : public OffsetGroup
{
private:
VersionInfoPrivate * d;
public:
enum OSType
{
OS_WINDOWS,
OS_LINUX,
OS_APPLE,
OS_BAD
};
VersionInfo();
VersionInfo(const VersionInfo&);
void copy(const DFHack::VersionInfo* old);

@ -1,10 +1,6 @@
#ifndef CL_MOD_ITEMS
#define CL_MOD_ITEMS
/*
* DEPRECATED, DO NOT USE UNTIL FURTHER NOTICE!
**/
/*
* Creatures
*/

@ -99,7 +99,17 @@ namespace DFHack
/// this is NOT part of the DF vein, but an address of the vein as seen by DFhack.
uint32_t address_of;
};
struct t_grassvein
{
uint32_t vtable;
/// material vector index
uint32_t material;
/// 16x16 array of covering 'intensity'
uint8_t intensity[16][16];
/// this is NOT part of the DF vein, but an address of the vein as seen by DFhack.
uint32_t address_of;
};
enum BiomeOffset
{
eNorthWest,
@ -148,7 +158,15 @@ namespace DFHack
liquid_water,
liquid_magma
};
/*
enum e_liquidcharacter
{
liquid_fresh,
liquid_unk1,
liquid_salt,
liquid_unk2,
};
*/
struct naked_designation
{
unsigned int flow_size : 3; // how much liquid is here?
@ -188,8 +206,9 @@ namespace DFHack
unsigned int feature_local : 1;
/// this tile is a part of a global feature. can be combined with 'featstone' tiles
unsigned int feature_global : 1;
/// those ripples on streams?
unsigned int liquid_character : 2;
unsigned int water_stagnant : 1;
unsigned int water_salt : 1;
// e_liquidcharacter liquid_character : 2;
};
union t_designation
@ -417,7 +436,9 @@ namespace DFHack
bool ReadVeins(uint32_t x, uint32_t y, uint32_t z,
std::vector<t_vein>* veins,
std::vector<t_frozenliquidvein>* ices = 0,
std::vector<t_spattervein>* splatter = 0);
std::vector<t_spattervein>* splatter = 0,
std::vector<t_grassvein>* grass = 0
);
private:
struct Private;

@ -145,7 +145,7 @@ namespace DFHack
void ReadAllMaterials(void);
std::string getType(t_material & mat);
std::string getType(t_material & mat);
std::string getDescription(t_material & mat);
private:
class Private;

@ -25,9 +25,9 @@ distribution.
#ifndef KEYS_H_INCLUDED
#define KEYS_H_INCLUDED
#include "dfhack/DFPragma.h"
#include "dfhack/DFExport.h"
#include "dfhack/DFModule.h"
#include "../DFPragma.h"
#include "../DFExport.h"
#include "../DFModule.h"
namespace DFHack
{

@ -72,24 +72,36 @@ Buildings::Buildings(DFContextShared * d_)
d = new Private;
d->d = d_;
d->owner = d_->p;
d->p_bld = NULL;
d->Inited = d->Started = d->hasCustomWorkshops = false;
VersionInfo * mem = d->d->offset_descriptor;
OffsetGroup * OG_build = mem->getGroup("Buildings");
d->buildings_vector = OG_build->getAddress ("buildings_vector");
d->Inited = true;
try
{
d->custom_workshop_vector = OG_build->getAddress("custom_workshop_vector");
d->building_custom_workshop_type = OG_build->getOffset("building_custom_workshop_type");
d->custom_workshop_type = OG_build->getOffset("custom_workshop_type");
d->custom_workshop_name = OG_build->getOffset("custom_workshop_name");
mem->resolveClassnameToClassID("building_custom_workshop", d->custom_workshop_id);
d->hasCustomWorkshops = true;
d->buildings_vector = OG_build->getAddress ("buildings_vector");
}
catch(DFHack::Error::UnsetMemoryDefinition &e)
catch(DFHack::Error::AllMemdef &e)
{
cerr << "Custom workshops not available. Unset Memory Definition: " << e.what() << endl;
cerr << "Buildings not available... " << e.what() << endl;
d->Inited = false;
}
if(d->Inited)
{
try
{
d->custom_workshop_vector = OG_build->getAddress("custom_workshop_vector");
d->building_custom_workshop_type = OG_build->getOffset("building_custom_workshop_type");
d->custom_workshop_type = OG_build->getOffset("custom_workshop_type");
d->custom_workshop_name = OG_build->getOffset("custom_workshop_name");
mem->resolveClassnameToClassID("building_custom_workshop", d->custom_workshop_id);
d->hasCustomWorkshops = true;
}
catch(DFHack::Error::AllMemdef &e)
{
cerr << "Custom workshops not available. Memory Definition: " << e.what() << endl;
}
}
d->Inited = true;
}
Buildings::~Buildings()
@ -101,6 +113,8 @@ Buildings::~Buildings()
bool Buildings::Start(uint32_t & numbuildings)
{
if(!d->Inited)
return false;
d->p_bld = new DfVector <uint32_t> (d->owner, d->buildings_vector);
numbuildings = d->p_bld->size();
d->Started = true;

@ -74,7 +74,7 @@ t_customWorkshop* Buildings_ReadCustomWorkshopTypes(DFHackObject* b_Ptr)
if(b_Ptr != NULL)
{
int i;
t_customWorkshop* cw_Ptr;
t_customWorkshop* cw_Ptr = NULL;
std::map<uint32_t, string> bTypes;
map<uint32_t, string>::iterator bIter;

@ -69,9 +69,10 @@ Creatures::Creatures(DFContextShared* _d)
{
d = new Private;
d->d = _d;
Process * p = d->owner = _d->p;
d->owner = _d->p;
d->Inited = false;
d->Started = false;
d->p_cre = NULL;
d->d->InitReadNames(); // throws on error
VersionInfo * minfo = d->d->offset_descriptor;
OffsetGroup *OG_Creatures = minfo->getGroup("Creatures");
@ -149,10 +150,14 @@ Creatures::~Creatures()
bool Creatures::Start( uint32_t &numcreatures )
{
d->p_cre = new DfVector <uint32_t> (d->owner, d->creatures.vector);
d->Started = true;
numcreatures = d->p_cre->size();
return true;
if(d->Ft_basic)
{
d->p_cre = new DfVector <uint32_t> (d->owner, d->creatures.vector);
d->Started = true;
numcreatures = d->p_cre->size();
return true;
}
return false;
}
bool Creatures::Finish()
@ -183,7 +188,6 @@ bool Creatures::ReadCreature (const int32_t index, t_creature & furball)
}
*/
// non-SHM slow path
VersionInfo * minfo = d->d->offset_descriptor;
// read pointer from vector at position
uint32_t temp = d->p_cre->at (index);
@ -471,6 +475,8 @@ bool Creatures::WriteSex(const uint32_t index, const uint8_t sex)
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->writeByte (temp + d->creatures.sex_offset, sex);
return true;
}
bool Creatures::WriteTraits(const uint32_t index, const t_soul &soul)
@ -596,7 +602,6 @@ bool Creatures::ReadJob(const t_creature * furball, vector<t_material> & mat)
if(!d->Inited) return false;
if(!furball->current_job.active) return false;
Process * p = d->owner;
VersionInfo * minfo = d->d->offset_descriptor;
DfVector <uint32_t> cmats(p, furball->current_job.occupationPtr + d->OG_jobs->getOffset("materials_vector"));
mat.resize(cmats.size());
@ -614,7 +619,6 @@ bool Creatures::ReadJob(const t_creature * furball, vector<t_material> & mat)
bool Creatures::ReadInventoryIdx(const uint32_t index, std::vector<uint32_t> & item)
{
if(!d->Started) return false;
Process * p = d->owner;
uint32_t temp = d->p_cre->at (index);
return this->ReadInventoryPtr(temp, item);
}

@ -84,7 +84,7 @@ t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball)
if(mat.size() <= 0)
return NULL;
t_material* buf;
t_material* buf = NULL;
(*alloc_t_material_buffer_callback)(buf, mat.size());
@ -104,6 +104,64 @@ t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball)
return NULL;
}
uint32_t* Creatures_ReadInventoryIdx(DFHackObject* cPtr, const uint32_t index)
{
if(cPtr != NULL)
{
std::vector<uint32_t> item;
if(((DFHack::Creatures*)cPtr)->ReadInventoryIdx(index, item))
{
if(item.size() <= 0)
return NULL;
uint32_t* buf = NULL;
(*alloc_uint_buffer_callback)(buf, item.size());
if(buf != NULL)
{
copy(item.begin(), item.end(), buf);
return buf;
}
else
return NULL;
}
}
return NULL;
}
uint32_t* Creatures_ReadInventoryPtr(DFHackObject* cPtr, const uint32_t index)
{
if(cPtr != NULL)
{
std::vector<uint32_t> item;
if(((DFHack::Creatures*)cPtr)->ReadInventoryPtr(index, item))
{
if(item.size() <= 0)
return NULL;
uint32_t* buf = NULL;
(*alloc_uint_buffer_callback)(buf, item.size());
if(buf != NULL)
{
copy(item.begin(), item.end(), buf);
return buf;
}
else
return NULL;
}
}
return NULL;
}
uint32_t Creatures_GetDwarfRaceIndex(DFHackObject* cPtr)
{
if(cPtr != NULL)

@ -0,0 +1,170 @@
// This is just a graveyard of old 40d code. Things in here COULD be turned into modules, but it requires research.
bool API::InitReadEffects ( uint32_t & numeffects )
{
if(d->effectsInited)
FinishReadEffects();
int effects = 0;
try
{
effects = d->offset_descriptor->getAddress ("effects_vector");
}
catch(Error::AllMemdef)
{
return false;
}
d->effectsInited = true;
d->p_effect = new DfVector (d->p, effects);
numeffects = d->p_effect->getSize();
return true;
}
bool API::ReadEffect(const uint32_t index, t_effect_df40d & effect)
{
if(!d->effectsInited)
return false;
if(index >= d->p_effect->getSize())
return false;
// read pointer from vector at position
uint32_t temp = d->p_effect->at (index);
//read effect from memory
d->p->read (temp, sizeof (t_effect_df40d), (uint8_t *) &effect);
return true;
}
// use with care!
bool API::WriteEffect(const uint32_t index, const t_effect_df40d & effect)
{
if(!d->effectsInited)
return false;
if(index >= d->p_effect->getSize())
return false;
// read pointer from vector at position
uint32_t temp = d->p_effect->at (index);
// write effect to memory
d->p->write(temp,sizeof(t_effect_df40d), (uint8_t *) &effect);
return true;
}
void API::FinishReadEffects()
{
if(d->p_effect)
{
delete d->p_effect;
d->p_effect = NULL;
}
d->effectsInited = false;
}
bool API::InitReadNotes( uint32_t &numnotes )
{
try
{
memory_info * minfo = d->offset_descriptor;
int notes = minfo->getAddress ("notes");
d->note_foreground_offset = minfo->getOffset ("note_foreground");
d->note_background_offset = minfo->getOffset ("note_background");
d->note_name_offset = minfo->getOffset ("note_name");
d->note_xyz_offset = minfo->getOffset ("note_xyz");
d->p_notes = new DfVector (d->p, notes);
d->notesInited = true;
numnotes = d->p_notes->getSize();
return true;
}
catch (Error::AllMemdef&)
{
d->notesInited = false;
numnotes = 0;
throw;
}
}
bool API::ReadNote (const int32_t index, t_note & note)
{
if(!d->notesInited) return false;
// read pointer from vector at position
uint32_t temp = d->p_notes->at (index);
note.symbol = d->p->readByte(temp);
note.foreground = d->p->readWord(temp + d->note_foreground_offset);
note.background = d->p->readWord(temp + d->note_background_offset);
d->p->readSTLString (temp + d->note_name_offset, note.name, 128);
d->p->read (temp + d->note_xyz_offset, 3*sizeof (uint16_t), (uint8_t *) &note.x);
return true;
}
bool API::InitReadSettlements( uint32_t & numsettlements )
{
if(!d->InitReadNames()) return false;
try
{
memory_info * minfo = d->offset_descriptor;
int allSettlements = minfo->getAddress ("settlements");
int currentSettlement = minfo->getAddress("settlement_current");
d->settlement_name_offset = minfo->getOffset ("settlement_name");
d->settlement_world_xy_offset = minfo->getOffset ("settlement_world_xy");
d->settlement_local_xy_offset = minfo->getOffset ("settlement_local_xy");
d->p_settlements = new DfVector (d->p, allSettlements);
d->p_current_settlement = new DfVector(d->p, currentSettlement);
d->settlementsInited = true;
numsettlements = d->p_settlements->getSize();
return true;
}
catch (Error::AllMemdef&)
{
d->settlementsInited = false;
numsettlements = 0;
throw;
}
}
bool API::ReadSettlement(const int32_t index, t_settlement & settlement)
{
if(!d->settlementsInited) return false;
if(!d->p_settlements->getSize()) return false;
// read pointer from vector at position
uint32_t temp = d->p_settlements->at (index);
settlement.origin = temp;
d->readName(settlement.name, temp + d->settlement_name_offset);
d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x);
d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1);
return true;
}
bool API::ReadCurrentSettlement(t_settlement & settlement)
{
if(!d->settlementsInited) return false;
if(!d->p_current_settlement->getSize()) return false;
uint32_t temp = d->p_current_settlement->at(0);
settlement.origin = temp;
d->readName(settlement.name, temp + d->settlement_name_offset);
d->p->read(temp + d->settlement_world_xy_offset, 2 * sizeof(int16_t), (uint8_t *) &settlement.world_x);
d->p->read(temp + d->settlement_local_xy_offset, 4 * sizeof(int16_t), (uint8_t *) &settlement.local_x1);
return true;
}
void API::FinishReadSettlements()
{
if(d->p_settlements)
{
delete d->p_settlements;
d->p_settlements = NULL;
}
if(d->p_current_settlement)
{
delete d->p_current_settlement;
d->p_current_settlement = NULL;
}
d->settlementsInited = false;
}
void API::FinishReadNotes()
{
if(d->p_notes)
{
delete d->p_notes;
d->p_notes = 0;
}
d->notesInited = false;
}

@ -58,6 +58,23 @@ int Gui_ReadPauseState(DFHackObject* gui)
return -1;
}
int Gui_SetPauseState(DFHackObject* gui, int8_t paused)
{
if(gui != NULL)
{
bool pauseState = false;
if(paused > 0)
pauseState = true;
((DFHack::Gui*)gui)->SetPauseState(pauseState);
return 1;
}
return -1;
}
int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen)
{
if(gui != NULL)

@ -116,6 +116,21 @@ Accessor::Accessor(uint32_t function, Process *p)
this->offset1 = (funcText>>24) & 0xffff;
return;
}
if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL )
{
/* mov ax, [ecx+xx]; ret; (shorter instruction)*/
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>24) & 0xff;
return;
}
if( (funcText&0x00000000FF00FFFFLL) == 0x00000000C300418BLL )
{
/* mov eax, [ecx+xx]; ret; */
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>16) & 0xff;
this->dataWidth = 4;
return;
}
if( (funcText&0xFFFFFFFF0000FFFFLL) == 0x8B6600000000818BLL )
{
uint64_t funcText2 = p->readQuad(function+8);
@ -134,6 +149,13 @@ Accessor::Accessor(uint32_t function, Process *p)
this->offset1 = (funcText>>24) & 0xffff;
return;
}
if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C30041BF0FLL )
{
/* movsx eax, word ptr [ecx+xx]; ret (shorter opcode)*/
this->type = ACCESSOR_INDIRECT;
this->offset1 = (funcText>>24) & 0xff;
return;
}
if( (funcText&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL )
{
/* mov eax, [ecx+xx]; ret; */
@ -240,8 +262,17 @@ Items::Items(DFContextShared * d_)
d->d = d_;
d->owner = d_->p;
}
bool Items::Start(){return true;}
bool Items::Finish(){return true;}
bool Items::Start()
{
return true;
}
bool Items::Finish()
{
return true;
}
Items::~Items()
{
Finish();
@ -250,6 +281,7 @@ Items::~Items()
while (it != d->descVTable.end())
{
delete (*it).second;
++it;
}
d->descType.clear();
d->descVTable.clear();
@ -262,10 +294,10 @@ bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item)
Process * p = d->owner;
ItemDesc * desc;
it = d->descVTable.find(itemptr);
if(it==d->descVTable.end())
uint32_t vtable = p->readDWord(itemptr);
it = d->descVTable.find(vtable);
if(it == d->descVTable.end())
{
uint32_t vtable = p->readDWord(itemptr);
desc = new ItemDesc(vtable, p);
d->descVTable[vtable] = desc;
d->descType[desc->mainType] = desc;
@ -282,7 +314,7 @@ std::string Items::getItemClass(int32_t index)
std::string out;
it = d->descType.find(index);
if(it==d->descType.end())
if(it == d->descType.end())
{
/* these are dummy values for mood decoding */
switch(index)
@ -325,3 +357,126 @@ std::string Items::getItemDescription(uint32_t itemptr, Materials * Materials)
out.append(this->getItemClass(item.matdesc.itemType));
return out;
}
// The OLD items code follows (40d era)
// TODO: merge with the current Items module
/*
bool API::InitReadItems(uint32_t & numitems)
{
try
{
int items = d->offset_descriptor->getAddress ("items");
d->item_material_offset = d->offset_descriptor->getOffset ("item_materials");
d->p_itm = new DfVector (d->p, items);
d->itemsInited = true;
numitems = d->p_itm->getSize();
return true;
}
catch (Error::AllMemdef&)
{
d->itemsInited = false;
numitems = 0;
throw;
}
}
bool API::getItemIndexesInBox(vector<uint32_t> &indexes,
const uint16_t x1, const uint16_t y1, const uint16_t z1,
const uint16_t x2, const uint16_t y2, const uint16_t z2)
{
if(!d->itemsInited) return false;
indexes.clear();
uint32_t size = d->p_itm->getSize();
struct temp2{
uint16_t coords[3];
uint32_t flags;
};
temp2 temp2;
for(uint32_t i =0;i<size;i++){
uint32_t temp = d->p_itm->at(i);
d->p->read(temp+sizeof(uint32_t),5 * sizeof(uint16_t), (uint8_t *) &temp2);
if(temp2.flags & (1 << 0)){
if (temp2.coords[0] >= x1 && temp2.coords[0] < x2)
{
if (temp2.coords[1] >= y1 && temp2.coords[1] < y2)
{
if (temp2.coords[2] >= z1 && temp2.coords[2] < z2)
{
indexes.push_back(i);
}
}
}
}
}
return true;
}
bool API::ReadItem (const uint32_t index, t_item & item)
{
if (!d->itemsInited) return false;
t_item_df40d item_40d;
// read pointer from vector at position
uint32_t temp = d->p_itm->at (index);
//read building from memory
d->p->read (temp, sizeof (t_item_df40d), (uint8_t *) &item_40d);
// transform
int32_t type = -1;
d->offset_descriptor->resolveObjectToClassID (temp, type);
item.origin = temp;
item.vtable = item_40d.vtable;
item.x = item_40d.x;
item.y = item_40d.y;
item.z = item_40d.z;
item.type = type;
item.ID = item_40d.ID;
item.flags.whole = item_40d.flags;
//TODO certain item types (creature based, threads, seeds, bags do not have the first matType byte, instead they have the material index only located at 0x68
d->p->read (temp + d->item_material_offset, sizeof (t_matglossPair), (uint8_t *) &item.material);
//for(int i = 0; i < 0xCC; i++){ // used for item research
// uint8_t byte = MreadByte(temp+i);
// item.bytes.push_back(byte);
//}
return true;
}
void API::FinishReadItems()
{
if(d->p_itm)
{
delete d->p_itm;
d->p_itm = NULL;
}
d->itemsInited = false;
}
*/
/*
bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes)
{
memory_info * minfo = d->offset_descriptor;
int matgloss_address = minfo->getAddress("matgloss");
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->p, matgloss_address + i*matgloss_skip);
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->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);
}
itemTypes.push_back(typesForVec);
}
return true;
}
*/

@ -58,7 +58,7 @@ char* Items_getItemDescription(DFHackObject* items, uint32_t itemptr, DFHackObje
if(desc.size() > 0)
{
char* buf;
char* buf = NULL;
(*alloc_char_buffer_callback)(buf,desc.size());
if(buf != NULL)
@ -86,7 +86,7 @@ char* Items_getItemClass(DFHackObject* items, int32_t index)
if(iclass.size() > 0)
{
char* buf;
char* buf = NULL;
(*alloc_char_buffer_callback)(buf, iclass.size());
if(buf != NULL)
{

@ -57,6 +57,8 @@ struct Maps::Private
OffsetGroup *OG_vector;
bool Inited;
bool Started;
bool hasGeology;
bool hasFeatures;
// map between feature address and the read object
map <uint32_t, t_feature> local_feature_store;
@ -74,6 +76,7 @@ Maps::Maps(DFContextShared* _d)
DFHack::VersionInfo * mem = p->getDescriptor();
Server::Maps::maps_offsets &off = d->offsets;
d->hasFeatures = d->hasGeology = true;
// get the offsets once here
OffsetGroup *OG_Maps = mem->getGroup("Maps");
@ -87,7 +90,6 @@ Maps::Maps(DFContextShared* _d)
off.region_z_offset = OG_Maps->getAddress ("region_z");
off.world_size_x = OG_Maps->getAddress ("world_size_x");
off.world_size_y = OG_Maps->getAddress ("world_size_y");
OffsetGroup *OG_MapBlock = OG_Maps->getGroup("block");
{
off.tile_type_offset = OG_MapBlock->getOffset ("type");
@ -100,18 +102,31 @@ Maps::Maps(DFContextShared* _d)
off.temperature1_offset = OG_MapBlock->getOffset ("temperature1");
off.temperature2_offset = OG_MapBlock->getOffset ("temperature2");
}
OffsetGroup *OG_Geology = OG_Maps->getGroup("geology");
try
{
off.world_regions = OG_Geology->getAddress ("ptr2_region_array");
off.region_size = OG_Geology->getHexValue ("region_size");
off.region_geo_index_offset = OG_Geology->getOffset ("region_geo_index_off");
off.geolayer_geoblock_offset = OG_Geology->getOffset ("geolayer_geoblock_offset");
off.world_geoblocks_vector = OG_Geology->getAddress ("geoblock_vector");
off.type_inside_geolayer = OG_Geology->getOffset ("type_inside_geolayer");
OffsetGroup *OG_Geology = OG_Maps->getGroup("geology");
{
off.world_regions = OG_Geology->getAddress ("ptr2_region_array");
off.region_size = OG_Geology->getHexValue ("region_size");
off.region_geo_index_offset = OG_Geology->getOffset ("region_geo_index_off");
off.geolayer_geoblock_offset = OG_Geology->getOffset ("geolayer_geoblock_offset");
off.world_geoblocks_vector = OG_Geology->getAddress ("geoblock_vector");
off.type_inside_geolayer = OG_Geology->getOffset ("type_inside_geolayer");
}
}
catch(Error::AllMemdef &)
{
d->hasGeology = false;
}
try
{
d->OG_global_features = OG_Maps->getGroup("features")->getGroup("global");
d->OG_local_features = OG_Maps->getGroup("features")->getGroup("local");
}
catch(Error::AllMemdef &)
{
d->hasFeatures = false;
}
d->OG_global_features = OG_Maps->getGroup("features")->getGroup("global");
d->OG_local_features = OG_Maps->getGroup("features")->getGroup("local");
}
d->OG_vector = mem->getGroup("vector");
@ -121,6 +136,10 @@ Maps::Maps(DFContextShared* _d)
mem->resolveClassnameToVPtr("block_square_event_frozen_liquid", off.vein_ice_vptr);
off.vein_mineral_vptr = 0;
mem->resolveClassnameToVPtr("block_square_event_mineral",off.vein_mineral_vptr);
off.vein_spatter_vptr = 0;
mem->resolveClassnameToVPtr("block_square_event_material_spatterst",off.vein_spatter_vptr);
off.vein_grass_vptr = 0;
mem->resolveClassnameToVPtr("block_square_event_grassst",off.vein_grass_vptr);
// upload offsets to SHM server if possible
d->maps_module = 0;
@ -517,18 +536,20 @@ bool Maps::WriteGlobalFeature(uint32_t x, uint32_t y, uint32_t z, int16_t global
/*
* Block events
*/
bool Maps::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector <t_vein>* veins, vector <t_frozenliquidvein>* ices, vector <t_spattervein> *splatter)
bool Maps::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector <t_vein>* veins, vector <t_frozenliquidvein>* ices, vector <t_spattervein> *splatter, vector <t_grassvein> *grass)
{
MAPS_GUARD
t_vein v;
t_frozenliquidvein fv;
t_spattervein sv;
t_grassvein gv;
Process* p = d->owner;
uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z];
if(veins) veins->clear();
if(ices) ices->clear();
if(splatter) splatter->clear();
if(grass) splatter->clear();
Server::Maps::maps_offsets &off = d->offsets;
if (addr)
@ -568,6 +589,14 @@ try_again:
// store it in the vector
splatter->push_back (sv);
}
else if(grass && type == off.vein_grass_vptr)
{
// read the splatter vein data (dereference pointer)
p->read (temp, sizeof(t_grassvein), (uint8_t *) &gv);
gv.address_of = temp;
// store it in the vector
grass->push_back (gv);
}
else
{
string cname = p->readClassName(type);
@ -586,6 +615,11 @@ try_again:
off.vein_spatter_vptr = type;
goto try_again;
}
else if(grass && cname=="block_square_event_grassst")
{
off.vein_grass_vptr = type;
goto try_again;
}
#ifdef DEBUG
else
{
@ -661,7 +695,7 @@ __int16 __userpurge GetGeologicalRegion<ax>(__int16 block_X<cx>, int X<ebx>, __i
bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
{
MAPS_GUARD
VersionInfo * minfo = d->d->offset_descriptor;
if(!d->hasGeology) return false;
Process *p = d->owner;
// get needed addresses and offsets. Now this is what I call crazy.
uint16_t worldSizeX, worldSizeY;
@ -731,12 +765,12 @@ bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
bool Maps::ReadLocalFeatures( std::map <planecoord, std::vector<t_feature *> > & local_features )
{
MAPS_GUARD
if(!d->hasFeatures) return false;
// can't be used without a map!
if(!d->block)
return false;
Process * p = d->owner;
VersionInfo * mem = p->getDescriptor();
// deref pointer to the humongo-structure
uint32_t base = p->readDWord(d->OG_local_features->getAddress("start_ptr"));
if(!base)
@ -824,6 +858,7 @@ bool Maps::ReadLocalFeatures( std::map <planecoord, std::vector<t_feature *> > &
bool Maps::ReadGlobalFeatures( std::vector <t_feature> & features)
{
MAPS_GUARD
if(!d->hasFeatures) return false;
// can't be used without a map!
if(!d->block)
return false;

@ -22,6 +22,7 @@ must not be misrepresented as being the original software.
distribution.
*/
#include "dfhack/DFPragma.h"
#include <vector>
#include <algorithm>
@ -54,6 +55,48 @@ int Maps_Finish(DFHackObject* maps)
return -1;
}
uint16_t* Maps_ReadGeology(DFHackObject* maps)
{
if(maps != NULL)
{
std::vector < std::vector <uint16_t> > geology;
if(((DFHack::Maps*)maps)->ReadGeology(geology))
{
uint16_t* buf = NULL;
uint32_t geoLength = 0;
for(unsigned int i = 0; i < geology.size(); i++)
{
for(unsigned int j = 0; j < geology[i].size(); j++)
{
geoLength += geology[i].size();
}
}
(*alloc_ushort_buffer_callback)(buf, geoLength);
if(buf != NULL)
{
uint16_t* bufCopyPtr = buf;
for(unsigned int i = 0; i < geology.size(); i++)
{
copy(geology[i].begin(), geology[i].end(), bufCopyPtr);
bufCopyPtr += geology[i].size();
}
return buf;
}
else
return NULL;
}
}
return NULL;
}
t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps)
{
if(maps != NULL)
@ -65,7 +108,7 @@ t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps)
if(featureVec.size() <= 0)
return NULL;
t_feature* buf;
t_feature* buf = NULL;
(*alloc_t_feature_buffer_callback)(buf, featureVec.size());
@ -255,6 +298,8 @@ int Maps_WriteEmptyLocalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint
{
return ((DFHack::Maps*)maps)->WriteLocalFeature(x, y, z, -1);
}
return -1;
}
int Maps_WriteGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int16_t local)
@ -273,6 +318,8 @@ int Maps_WriteEmptyGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uin
{
return ((DFHack::Maps*)maps)->WriteGlobalFeature(x, y, z, -1);
}
return -1;
}
int Maps_ReadBlockFlags(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_blockflags* blockflags)

@ -402,7 +402,7 @@ bool Materials::ReadCreatureTypesEx (void)
p->readSTLString (caste_start + sizeof_string, caste.singular, sizeof(caste.singular));
p->readSTLString (caste_start + 2 * sizeof_string, caste.plural, sizeof(caste.plural));
p->readSTLString (caste_start + 3 * sizeof_string, caste.adjective, sizeof(caste.adjective));
cout << "Caste " << caste.rawname << " " << caste.singular << ": 0x" << hex << caste_start << endl;
//cout << "Caste " << caste.rawname << " " << caste.singular << ": 0x" << hex << caste_start << endl;
if(have_advanced)
{
/* color mod reading */
@ -459,7 +459,7 @@ void Materials::ReadAllMaterials(void)
this->ReadCreatureTypes();
this->ReadCreatureTypesEx();
this->ReadDescriptorColors();
//this->ReadOthers();
this->ReadOthers();
}
std::string Materials::getDescription(t_material & mat)
@ -478,6 +478,12 @@ std::string Materials::getDescription(t_material & mat)
{
if (mat.subIndex>=this->other.size())
{
if (mat.itemType == 0) {
if(mat.subIndex<0)
return "any inorganic";
else
return this->inorganic[mat.subIndex].id;
}
if(mat.subIndex<0)
return "any";
if(mat.subIndex>=this->raceEx.size())

@ -232,7 +232,7 @@ t_matgloss* Materials_getInorganic(DFHackObject* mat)
if(materials->inorganic.size() > 0)
{
t_matgloss* buf;
t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->inorganic.size()));
@ -256,7 +256,7 @@ t_matgloss* Materials_getOrganic(DFHackObject* mat)
if(materials->organic.size() > 0)
{
t_matgloss* buf;
t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->organic.size()));
@ -280,7 +280,7 @@ t_matgloss* Materials_getTree(DFHackObject* mat)
if(materials->tree.size() > 0)
{
t_matgloss* buf;
t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->tree.size()));
@ -304,7 +304,7 @@ t_matgloss* Materials_getPlant(DFHackObject* mat)
if(materials->plant.size() > 0)
{
t_matgloss* buf;
t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->plant.size()));
@ -328,7 +328,7 @@ t_matgloss* Materials_getRace(DFHackObject* mat)
if(materials->race.size() > 0)
{
t_matgloss* buf;
t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->race.size()));
@ -354,7 +354,7 @@ c_creaturetype* Materials_getRaceEx(DFHackObject* mat)
if(matSize > 0)
{
c_creaturetype* buf;
c_creaturetype* buf = NULL;
((*alloc_creaturetype_buffer_callback)(buf, matSize));
@ -379,7 +379,7 @@ t_descriptor_color* Materials_getColor(DFHackObject* mat)
if(materials->color.size() > 0)
{
t_descriptor_color* buf;
t_descriptor_color* buf = NULL;
((*alloc_descriptor_buffer_callback)(buf, materials->color.size()));
@ -403,7 +403,7 @@ t_matglossOther* Materials_getOther(DFHackObject* mat)
if(materials->other.size() > 0)
{
t_matglossOther* buf;
t_matglossOther* buf = NULL;
((*alloc_matgloss_other_buffer_callback)(buf, materials->other.size()));
@ -427,7 +427,7 @@ t_matgloss* Materials_getAllDesc(DFHackObject* mat)
if(materials->alldesc.size() > 0)
{
t_matgloss* buf;
t_matgloss* buf = NULL;
((*alloc_matgloss_buffer_callback)(buf, materials->alldesc.size()));

@ -102,7 +102,7 @@ t_hotkey* Position_ReadHotkeys(DFHackObject* pos)
{
if(pos != NULL)
{
t_hotkey* buf;
t_hotkey* buf = NULL;
(*alloc_t_hotkey_buffer_callback)(buf, NUM_HOTKEYS);
@ -144,7 +144,7 @@ t_screen* Position_getScreenTiles(DFHackObject* pos, int32_t width, int32_t heig
{
if(pos != NULL)
{
t_screen* buf;
t_screen* buf = NULL;
(*alloc_t_screen_buffer_callback)(buf, width * height);

@ -124,7 +124,7 @@ char* Translation_TranslateNameEnglish(DFHackObject* trans, const DFHack::t_name
if(nameTrans.size() > 0)
{
char* buf;
char* buf = NULL;
(*alloc_char_buffer_callback)(buf, nameTrans.size());
@ -155,7 +155,7 @@ char* Translation_TranslateNameNonEnglish(DFHackObject* trans, const DFHack::t_n
if(nameTrans.size() > 0)
{
char* buf;
char* buf = NULL;
(*alloc_char_buffer_callback)(buf, nameTrans.size());

@ -130,20 +130,19 @@ WindowIO::~WindowIO ()
void WindowIO::TypeStr (const char *input, int delay, bool useShift)
{
//sendmessage needs a window handle HWND, so have to get that from the process HANDLE
HWND currentWindow = GetForegroundWindow();
window myWindow;
myWindow.pid = d->p->getPID();
EnumWindows (EnumWindowsProc, (LPARAM) &myWindow);
char cChar;
DWORD dfProccess = GetWindowThreadProcessId(myWindow.windowHandle,NULL);
DWORD currentProccess = GetWindowThreadProcessId(currentWindow,NULL);
AttachThreadInput(currentProccess,dfProccess,TRUE); //The two threads have to have attached input in order to change the keyboard state, which is needed to set the shift state
DWORD dfProcess = GetWindowThreadProcessId(myWindow.windowHandle,NULL);
DWORD currentProcess = GetCurrentThreadId();
AttachThreadInput(currentProcess,dfProcess,TRUE); //The two threads have to have attached input in order to change the keyboard state, which is needed to set the shift state
while ( (cChar = *input++)) // loops through chars
{
short vk = VkKeyScan (cChar); // keycode of char
if (useShift || (vk >> 8) &1) // char is capital, so need to hold down shift
{
vk = vk & 0xFF; // remove the shift state from the virtual key code
BYTE keybstate[256] = {0};
BYTE keybstateOrig[256] = {0};
GetKeyboardState((LPBYTE)&keybstateOrig);
@ -160,7 +159,7 @@ void WindowIO::TypeStr (const char *input, int delay, bool useShift)
SendMessage(myWindow.windowHandle,WM_KEYUP,vk,0);
}
}
AttachThreadInput(currentProccess,dfProccess,FALSE); //detach the threads
AttachThreadInput(currentProcess,dfProcess,FALSE); //detach the threads
Sleep (delay);
}

@ -81,6 +81,57 @@ using namespace std;
#include <winnt.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <Dbghelp.h>
typedef LONG NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
// FIXME: it is uncertain how these map to 64bit
typedef struct _DEBUG_BUFFER
{
HANDLE SectionHandle;
PVOID SectionBase;
PVOID RemoteSectionBase;
ULONG SectionBaseDelta;
HANDLE EventPairHandle;
ULONG Unknown[2];
HANDLE RemoteThreadHandle;
ULONG InfoClassMask;
ULONG SizeOfInfo;
ULONG AllocatedSize;
ULONG SectionSize;
PVOID ModuleInformation;
PVOID BackTraceInformation;
PVOID HeapInformation;
PVOID LockInformation;
PVOID Reserved[8];
} DEBUG_BUFFER, *PDEBUG_BUFFER;
typedef struct _DEBUG_HEAP_INFORMATION
{
ULONG Base; // 0×00
ULONG Flags; // 0×04
USHORT Granularity; // 0×08
USHORT Unknown; // 0x0A
ULONG Allocated; // 0x0C
ULONG Committed; // 0×10
ULONG TagCount; // 0×14
ULONG BlockCount; // 0×18
ULONG Reserved[7]; // 0x1C
PVOID Tags; // 0×38
PVOID Blocks; // 0x3C
} DEBUG_HEAP_INFORMATION, *PDEBUG_HEAP_INFORMATION;
// RtlQueryProcessDebugInformation.DebugInfoClassMask constants
#define PDI_MODULES 0x01
#define PDI_BACKTRACE 0x02
#define PDI_HEAPS 0x04
#define PDI_HEAP_TAGS 0x08
#define PDI_HEAP_BLOCKS 0x10
#define PDI_LOCKS 0x20
extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlQueryProcessDebugInformation( IN ULONG ProcessId, IN ULONG DebugInfoClassMask, IN OUT PDEBUG_BUFFER DebugBuffer);
extern "C" __declspec(dllimport) PDEBUG_BUFFER __stdcall RtlCreateQueryDebugBuffer( IN ULONG Size, IN BOOLEAN EventPair);
extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlDestroyQueryDebugBuffer( IN PDEBUG_BUFFER DebugBuffer);
#endif
// dfhack dependencies

@ -0,0 +1,96 @@
/*
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 LINUX_PROCESS_H_INCLUDED
#define LINUX_PROCESS_H_INCLUDED
#ifdef LINUX_BUILD
#include "dfhack/DFProcess.h"
namespace DFHack
{
class LinuxProcessBase : public Process
{
protected:
VersionInfo * my_descriptor;
pid_t my_pid;
string memFile;
int memFileHandle;
bool attached;
bool suspended;
bool identified;
public:
LinuxProcessBase(uint32_t pid);
~LinuxProcessBase();
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
void readFloat(const uint32_t address, float & value);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
VersionInfo *getDescriptor();
int getPID();
std::string getPath();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { OUTPUT=0; return false;};
// get the SHM start if available
char * getSHMStart (void){return 0;};
// set a SHM command and wait for a response
bool SetAndWait (uint32_t state){return false;};
};
}
#endif
#endif

@ -0,0 +1,46 @@
/*
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 <string>
namespace DFHack {
class Process;
class MicrosoftSTL
{
private:
uint32_t STLSTR_buf_off;
uint32_t STLSTR_size_off;
uint32_t STLSTR_cap_off;
Process* p;
public:
void init(Process* p);
const std::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){};
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
};
}

@ -0,0 +1,38 @@
/*
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 PROCESS_FACTORY_H_INCLUDED
#define PROCESS_FACTORY_H_INCLUDED
#include "dfhack/DFProcess.h"
namespace DFHack
{
Process* createNormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
Process* createSHMProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
#ifdef LINUX_BUILD
Process* createWineProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions);
#endif
}
#endif

@ -0,0 +1,144 @@
/*
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 SHM_PROCESS_H_INCLUDED
#define SHM_PROCESS_H_INCLUDED
#include "dfhack/DFProcess.h"
#include "dfhack/DFIntegers.h"
namespace DFHack
{
class DFHACK_EXPORT SHMProcess : public Process
{
private:
class Private;
Private * const d;
public:
SHMProcess(uint32_t PID, std::vector <VersionInfo *> & known_versions);
~SHMProcess();
// Set up stuff so we can read memory
bool attach();
bool detach();
bool suspend();
bool asyncSuspend();
bool resume();
bool forceresume();
void readQuad(const uint32_t address, uint64_t & value);
void writeQuad(const uint32_t address, const uint64_t value);
void readDWord(const uint32_t address, uint32_t & value);
void writeDWord(const uint32_t address, const uint32_t value);
void readFloat(const uint32_t address, float & value);
void readWord(const uint32_t address, uint16_t & value);
void writeWord(const uint32_t address, const uint16_t value);
void readByte(const uint32_t address, uint8_t & value);
void writeByte(const uint32_t address, const uint8_t value);
void read( uint32_t address, uint32_t length, uint8_t* buffer);
void write(uint32_t address, uint32_t length, uint8_t* buffer);
const std::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);
// get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr);
const std::string readCString (uint32_t offset);
bool isSuspended();
bool isAttached();
bool isIdentified();
bool getThreadIDs(std::vector<uint32_t> & threads );
void getMemRanges(std::vector<t_memrange> & ranges );
VersionInfo *getDescriptor();
int getPID();
std::string getPath();
// get module index by name and version. bool 1 = error
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT);
// get the SHM start if available
char * getSHMStart (void);
bool SetAndWait (uint32_t state);
private:
bool acquireSuspendLock();
bool releaseSuspendLock();
};
class SHMProcess::Private
{
public:
Private(SHMProcess * self_);
~Private(){}
VersionInfo * memdescriptor;
SHMProcess * self;
char *shm_addr;
int attachmentIdx;
bool attached;
bool locked;
bool identified;
bool useYield;
#ifdef LINUX_BUILD
pid_t process_ID;
int shm_ID;
int server_lock;
int client_lock;
int suspend_lock;
#else
typedef uint32_t pid_t;
uint32_t process_ID;
HANDLE DFSVMutex;
HANDLE DFCLMutex;
HANDLE DFCLSuspendMutex;
#endif
bool validate(std::vector< VersionInfo* >& known_versions);
bool Aux_Core_Attach(bool & versionOK, pid_t& PID);
bool SetAndWait (uint32_t state);
bool GetLocks();
bool AreLocksOk();
void FreeLocks();
};
}
// some helpful macros to keep the code bloat in check
#define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx]
#define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx]
#define SHMHDR ((shm_core_hdr *)shm_addr)
#define D_SHMHDR ((shm_core_hdr *)(d->shm_addr))
#define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER))
#define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER))
#endif

@ -57,6 +57,7 @@ typedef struct
uint32_t vein_mineral_vptr;
uint32_t vein_ice_vptr;
uint32_t vein_spatter_vptr;
uint32_t vein_grass_vptr;
/*
GEOLOGY
*/

@ -302,7 +302,15 @@ void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature)
{
cout << ", ";
}
cout << mem->getSkill(creature.defaultSoul.skills[i].id) << ": " << creature.defaultSoul.skills[i].rating;
try
{
cout << mem->getSkill(creature.defaultSoul.skills[i].id) << ": " << creature.defaultSoul.skills[i].rating;
}
catch(DFHack::Error::AllMemdef &e)
{
cout << "Unknown skill! : " << creature.defaultSoul.skills[i].id <<", rating: " << creature.defaultSoul.skills[i].rating << endl;
cout << e.what() << endl;
}
}
cout << endl;
cout << "Traits" << endl;

@ -2,6 +2,12 @@
* dumps vtables, items types and class name for all items in game
* best used this way : ./dfitemdump | sort -ug
*/
// THIS IS NOT A GOOD EXAMPLE!
// ... just look at all the magic numbers.
// I'm not fixing it though.
// ~px
#include <stdio.h>
#include <iostream>
#include <iomanip>
@ -41,7 +47,8 @@ int main ()
Materials = DF->getMaterials();
Materials->ReadAllMaterials();
p = DF->getProcess();
DFHack::DfVector <uint32_t> p_items (p, p->getDescriptor()->getAddress ("items_vector"));
DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
DFHack::DfVector <uint32_t> p_items (p, itemGroup->getAddress("items_vector"));
uint32_t size = p_items.size();
Items = DF->getItems();
@ -49,6 +56,7 @@ int main ()
printf("type\tvtable\tname\tquality\tdecorate\n");
for (i=0;i<size;i++)
{
uint32_t curItem = p_items[i];
uint32_t vtable = p->readDWord(p_items[i]);
uint32_t func0 = p->readDWord(vtable);
uint64_t funct0 = p->readQuad(func0);
@ -84,6 +92,8 @@ int main ()
if (funct1 == 0xC300000092818B66LL)
quality = p->readWord(p_items[i]+0x92);
if (funct1 == 0xC300000082818B66LL)
quality = p->readWord(p_items[i]+0x82);
else if (funct1 == 0xCCCCCCCCCCC3C033LL)
quality = 0;
else
@ -115,6 +125,11 @@ int main ()
uint32_t off1 = (funcBt>>24) & 0xffff;
typeB = p->readWord(p_items[i] + off1);
}
else if ( (funcBt&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL )
{
uint32_t off1 = (funcBt>>24) & 0xff;
typeB = p->readWord(p_items[i] + off1);
}
else
printf("bad typeB func @%p\n", (void*) funcB);
}
@ -126,6 +141,16 @@ int main ()
uint32_t off1 = (funcCt>>24)&0xffff;
typeC = p->readWord(p_items[i] + off1);
}
else if ( (funcCt&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL )
{
uint32_t off1 = (funcCt>>24) & 0xff;
typeC = p->readWord(p_items[i] + off1);
}
else if ( (funcCt&0x00000000FF00FFFFLL) == 0x00000000C300418BLL )
{
uint32_t off1 = (funcCt>>16) & 0xff;
typeC = p->readWord(p_items[i] + off1);
}
else
printf("bad typeC func @%p\n", (void*) funcC);
@ -134,12 +159,27 @@ int main ()
else if ( (funcDt&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL )
{
uint32_t off1 = (funcDt>>16) & 0xffff;
typeD = p->readDWord(p_items[i] + off1);
typeD = p->readWord(p_items[i] + off1);
}
else if ( (funcDt&0xFFFFFF0000FFFFFFLL) == 0xC30000000081BF0FLL )
{
uint32_t off1 = (funcDt>>24) & 0xffff;
typeD = (int16_t) p->readWord(p_items[i] + off1);
typeD = p->readWord(p_items[i] + off1);
}
else if ( (funcDt&0x000000FF00FFFFFFLL) == 0x000000C30041BF0FLL )
{
uint32_t off1 = (funcDt>>24) & 0xff;
typeD = p->readWord(p_items[i] + off1);
}
else if ( (funcDt&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL )
{
uint32_t off1 = (funcDt>>24) & 0xff;
typeD = p->readWord(p_items[i] + off1);
}
else if ( (funcDt&0x00000000FF00FFFFLL) == 0x00000000C300418BLL )
{
uint32_t off1 = (funcDt>>16) & 0xff;
typeD = p->readDWord(p_items[i] + off1);
}
else
printf("bad typeD func @%p\n", (void*) funcD);
@ -155,8 +195,8 @@ int main ()
{
bool sep = false;
printf("\tdeco=[");
uint32_t decStart = p->readDWord(p_items[i] + 0xAC);
uint32_t decEnd = p->readDWord(p_items[i] + 0xB0);
uint32_t decStart = p->readDWord(p_items[i] + 0x90); // 0xAC pre .13
uint32_t decEnd = p->readDWord(p_items[i] + 0x94); // 0xB0 pre .13
if (decStart != decEnd)
{
for (j=decStart;j<decEnd;j+=4)

@ -24,19 +24,14 @@ TARGET_LINK_LIBRARIES(dfdigger dfhack)
ADD_EXECUTABLE(dfdigger2 digger2.cpp)
TARGET_LINK_LIBRARIES(dfdigger2 dfhack)
ADD_EXECUTABLE(primitives primitives.cpp)
# itemdesignator - change some item designations (dump, forbid, on-fire) for all
# items of a given type and material
# Author: belal
#ADD_EXECUTABLE(dfitemdesignator itemdesignator.cpp)
#TARGET_LINK_LIBRARIES(dfitemdesignator dfhack)
# incrementalsearch - a bit like cheat engine, only DF-specific, very basic
# and Linux-only
IF(UNIX)
ADD_EXECUTABLE(dfincremental incrementalsearch.cpp)
TARGET_LINK_LIBRARIES(dfincremental dfhack)
ENDIF(UNIX)
# catsplosion - Accelerates pregnancy
# Author: Zhentar
ADD_EXECUTABLE(dfcatsplosion catsplosion.cpp)
@ -60,6 +55,38 @@ TARGET_LINK_LIBRARIES(dfcatsplosion dfhack)
ADD_EXECUTABLE(dfcopypaste copypaste.cpp)
TARGET_LINK_LIBRARIES(dfcopypaste dfhack)
# paths
# Author: belal
# dumps the current path to the DF exe, as well as the relative paths to the
# current tileset and color files
ADD_EXECUTABLE(dfpaths paths.cpp)
TARGET_LINK_LIBRARIES(dfpaths dfhack)
# deramp
# Author: zilpin
# seeks entire map for 'remove ramp' designation, makes a floor, removes designation.
# intended use is to simulate old 'channel' functionality.
ADD_EXECUTABLE(dfderamp deramp.cpp)
TARGET_LINK_LIBRARIES(dfderamp dfhack)
# printtiletypes
# Author: zilpin
# Prints CSV dump of all tile type information.
# No DF process needed. Intended only for debugging and information purposes.
ADD_EXECUTABLE(dfprinttiletypes printtiletypes.cpp)
TARGET_LINK_LIBRARIES(dfprinttiletypes dfhack)
# hellhole
# Author: zilpin
# Creates a bottomless hole to hell.
# Experimental version hard-codes values.
# Will have many options in the future.
ADD_EXECUTABLE(dfhellhole hellhole.cpp)
TARGET_LINK_LIBRARIES(dfhellhole dfhack)
# this needs the C bindings
IF(BUILD_DFHACK_C_BINDINGS)
# for trying out some 'stuff'
@ -76,11 +103,8 @@ dfmoodump
dfdigger
dfdigger2
dfcatsplosion
dfderamp
dfprinttiletypes
dfhellhole
RUNTIME DESTINATION bin
)
IF(UNIX)
install(TARGETS
dfincremental
RUNTIME DESTINATION bin
)
ENDIF(UNIX)

@ -0,0 +1,137 @@
// De-ramp. All ramps marked for removal are replaced with given tile (presently, normal floor).
#include <iostream>
#include <vector>
#include <map>
#include <stddef.h>
#include <assert.h>
#include <string.h>
using namespace std;
#include <DFHack.h>
#include <dfhack/DFTileTypes.h>
int main (void)
{
uint32_t x_max,y_max,z_max;
uint32_t num_blocks = 0;
uint32_t bytes_read = 0;
DFHack::designations40d designations;
DFHack::tiletypes40d tiles;
DFHack::tiletypes40d tilesAbove;
//DFHack::TileRow *ptile;
int32_t oldT, newT;
int16_t t;
int dirty=0, count=0;
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF = DFMgr.getSingleContext();
//sanity check
assert( sizeof(designations) == (16*16*sizeof(DFHack::t_designation)) );
//Init
try
{
DF->Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::Maps *Mapz = DF->getMaps();
// init the map
if (!Mapz->Start())
{
cerr << "Can't init map." << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
Mapz->getSize(x_max,y_max,z_max);
uint8_t zeroes [16][16] = {0};
// walk the map
for (uint32_t x = 0; x< x_max;x++)
{
for (uint32_t y = 0; y< y_max;y++)
{
for (uint32_t z = 0; z< z_max;z++)
{
if (Mapz->isValidBlock(x,y,z))
{
dirty=0;
Mapz->ReadDesignations(x,y,z, &designations);
Mapz->ReadTileTypes(x,y,z, &tiles);
if (Mapz->isValidBlock(x,y,z+1))
{
Mapz->ReadTileTypes(x,y,z+1, &tilesAbove);
}
else
{
memset(&tilesAbove,0,sizeof(tilesAbove));
}
for (uint32_t ty=0;ty<16;++ty)
{
for (uint32_t tx=0;tx<16;++tx)
{
//Only the remove ramp designation (ignore channel designation, etc)
oldT = tiles[tx][ty];
if ( DFHack::designation_default == designations[tx][ty].bits.dig
&& DFHack::RAMP==DFHack::tileTypeTable[oldT].c)
{
//Current tile is a ramp.
//Set current tile, as accurately as can be expected
newT = DFHack::findSimilarTileType(oldT,DFHack::FLOOR);
//If no change, skip it (couldn't find a good tile type)
if ( oldT == newT) continue;
//Set new tile type, clear designation
tiles[tx][ty] = newT;
designations[tx][ty].bits.dig = DFHack::designation_no;
//Check the tile above this one, in case a downward slope needs to be removed.
if ( DFHack::RAMP_TOP == DFHack::tileTypeTable[tilesAbove[tx][ty]].c )
{
tilesAbove[tx][ty] = 32;
}
dirty=-1;
++count;
}
}
}
//If anything was changed, write it all.
if (dirty)
{
Mapz->WriteDesignations(x,y,z, &designations);
Mapz->WriteTileTypes(x,y,z, &tiles);
if (Mapz->isValidBlock(x,y,z+1))
{
Mapz->WriteTileTypes(x,y,z+1, &tilesAbove);
}
}
}
}
}
}
DF->Detach();
cout << "Found and changed " << count << " tiles." << endl;
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}

@ -21,7 +21,6 @@
#include <assert.h>
using namespace std;
#include <argstream.h>
#include <DFHack.h>
#include <dfhack/DFTileTypes.h>
#define BLOCK_SIZE 16

File diff suppressed because it is too large Load Diff

@ -0,0 +1,31 @@
#include <iostream>
using namespace std;
#include <DFHack.h>
using namespace DFHack;
int main ()
{
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF = DFMgr.getSingleContext();
try
{
DF->Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::Process * Process = DF->getProcess();
DFHack::Gui * gui = DF->getGui();
cout << Process->getPath() << endl;
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}

@ -0,0 +1,27 @@
#include <iostream>
#include <iomanip>
#include <climits>
#include <vector>
#include <sstream>
#include <ctime>
#include <cstdio>
using namespace std;
std::string teststr1;
std::string * teststr2;
std::string teststr3("test");
int main (int numargs, const char ** args)
{
printf("std::string E : 0x%x\n", &teststr1);
teststr1 = "This is a fairly long string, much longer than the one made by default constructor.";
cin.ignore();
printf("std::string L : 0x%x\n", &teststr1);
teststr1 = "This one is shorter";
cin.ignore();
printf("std::string S : 0x%x\n", &teststr1);
cin.ignore();
teststr2 = new string();
printf("std::string * : 0x%x\n", &teststr2);
printf("std::string(\"test\") : 0x%x\n", &teststr3);
cin.ignore();
return 0;
}

@ -0,0 +1,100 @@
// Prints all the Tile Types known by DFHack.
// File is both fixed-field and CSV parsable.
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <map>
#include <stddef.h>
#include <assert.h>
using namespace std;
#include <DFHack.h>
#include <dfhack/DFTileTypes.h>
using namespace DFHack;
int main (int argc, char **argv)
{
FILE *f=stdout;
const int Columns = 7;
const char * Headings[Columns] = {"TileTypeID","Class","Material","V","Special","Direction","Description"};
size_t Size[ Columns ] = {};
int i;
//First, figure out column widths.
for(i=0;i<Columns;++i)
{
Size[i]=strlen(Headings[i])+1;
}
//Classes
fprintf(f,"\nTile Type Classes:\n");
for(i=0;i<tileclass_count;++i)
{
Size[1]=max<size_t>(Size[1],strlen(TileClassString[i]));
fprintf(f,"%4i ; %s\n", i, TileClassString[i] ,0 );
}
//Materials
fprintf(f,"\nTile Type Materials:\n");
for(i=0;i<tilematerial_count;++i)
{
Size[2]=max<size_t>(Size[2],strlen(TileMaterialString[i]));
fprintf(f,"%4i ; %s\n", i, TileMaterialString[i] ,0 );
}
//Specials
fprintf(f,"\nTile Type Specials:\n");
for(i=0;i<tilespecial_count;++i)
{
Size[4]=max<size_t>(Size[4],strlen(TileSpecialString[i]));
fprintf(f,"%4i ; %s\n", i, TileSpecialString[i] ,0 );
}
/* - Not needed for now -
//Direction is tricky
for(i=0;i<TILE_TYPE_ARRAY_LENGTH;++i)
Size[5]=max(Size[5], tileTypeTable[i].d.sum()+1 );
*/
//Print the headings first.
fprintf(f,"\nTile Types:\n");
for(i=0;i<Columns;++i)
{
if(i) putc(';',f);
fprintf(f," %-*s ",Size[i],Headings[i],0);
}
fprintf(f,"\n");
//Process the whole array.
//A macro should be used for making the strings safe, but they are left in naked ? blocks
//to illustrate the array references more clearly.
for(i=0;i<TILE_TYPE_ARRAY_LENGTH;++i)
{
fprintf(f," %*i ; %-*s ; %-*s ; %*c ; %-*s ; %-*s ; %s\n",
Size[0], i,
Size[1], ( tileTypeTable[i].name ? TileClassString[ tileTypeTable[i].c ] : "" ),
Size[2], ( tileTypeTable[i].name ? TileMaterialString[ tileTypeTable[i].m ] : "" ),
Size[3], ( tileTypeTable[i].v ? '0'+tileTypeTable[i].v : ' ' ),
Size[4], ( tileTypeTable[i].s ? TileSpecialString[ tileTypeTable[i].s ] : "" ),
Size[5], ( tileTypeTable[i].d.whole ? tileTypeTable[i].d.getStr() : "" ),
( tileTypeTable[i].name ? tileTypeTable[i].name : "" ),
0
);
}
fprintf(f,"\n");
#ifndef LINUX_BUILD
if( 1== argc)
{
cout << "Done. Press any key to continue" << endl;
cin.ignore();
}
#endif
return 0;
}

@ -449,7 +449,7 @@ start:
uint32_t nickname = mem->getOffset("creature_name") + mem->getOffset("name_nickname");
p->writeSTLString(toChange.origin+nickname,changeString);
}
catch (DFHack::Error::MissingMemoryDefinition&)
catch (DFHack::Error::AllMemdef&)
{
cerr << "Writing creature nicknames unsupported in this version!" << endl;
}
@ -461,7 +461,7 @@ start:
uint32_t custom_prof = mem->getOffset("creature_custom_profession");
p->writeSTLString(toChange.origin+custom_prof,changeString);
}
catch (DFHack::Error::MissingMemoryDefinition&)
catch (DFHack::Error::AllMemdef&)
{
cerr << "Writing creature custom profession unsupported in this version!" << endl;
}

@ -9,6 +9,10 @@ ENDIF(UNIX)
ADD_EXECUTABLE(dfreveal reveal.cpp)
TARGET_LINK_LIBRARIES(dfreveal dfhack)
# force pause!
ADD_EXECUTABLE(dfpause forcepause.cpp)
TARGET_LINK_LIBRARIES(dfpause dfhack)
# prospector - produces a list of available materials and their quantities
ADD_EXECUTABLE(dfprospector prospector.cpp)
TARGET_LINK_LIBRARIES(dfprospector dfhack)
@ -68,6 +72,12 @@ TARGET_LINK_LIBRARIES(dfdoffsets dfhack)
ADD_EXECUTABLE(dfweather weather.cpp)
TARGET_LINK_LIBRARIES(dfweather dfhack)
# incrementalsearch - a bit like cheat engine, only DF-specific, very basic
ADD_EXECUTABLE(dfautosearch autosearch.cpp)
TARGET_LINK_LIBRARIES(dfautosearch dfhack)
ADD_EXECUTABLE(dfincremental incrementalsearch.cpp)
TARGET_LINK_LIBRARIES(dfincremental dfhack)
IF(UNIX)
SET(VEINLOOK_BUILT "NO")
@ -113,6 +123,7 @@ dfvdig
dfcleanmap
dfunstuck
dfprobe
dfpause
dfdoffsets
dfattachtest
dfcleartask
@ -121,5 +132,7 @@ dfsuspend
dfflows
dfliquids
dfweather
dfautosearch
dfincremental
RUNTIME DESTINATION bin
)

@ -1,5 +1,8 @@
#ifndef SEGMENTED_FINDER_H
#define SEGMENTED_FINDER_H
#include <malloc.h>
#include <iosfwd>
#include <iterator>
class SegmentedFinder;
class SegmentFinder
@ -9,18 +12,37 @@ class SegmentFinder
{
_DF = DF;
mr_ = mr;
mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start);
DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer);
_SF = SF;
if(mr.valid)
{
mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start);
_SF = SF;
try
{
DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer);
valid = true;
}
catch (DFHack::Error::MemoryAccessDenied &)
{
free(mr_.buffer);
valid = false;
mr.valid = false; // mark the range passed in as bad
cout << "Range 0x" << hex << mr_.start << " - 0x" << mr_.end << dec << " not readable." << endl;
}
}
}
~SegmentFinder()
{
delete mr_.buffer;
if(valid)
free(mr_.buffer);
}
bool isValid()
{
return valid;
}
template <class needleType, class hayType, typename comparator >
bool Find (needleType needle, const uint8_t increment , vector <uint64_t> &newfound, comparator oper)
{
if(!valid) return !newfound.empty();
//loop
for(uint64_t offset = 0; offset < (mr_.end - mr_.start) - sizeof(hayType); offset += increment)
{
@ -33,6 +55,7 @@ class SegmentFinder
template < class needleType, class hayType, typename comparator >
uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length)
{
if(!valid) return 0;
uint64_t stopper = min((mr_.end - mr_.start) - sizeof(hayType), (start - mr_.start) - sizeof(hayType) + length);
//loop
for(uint64_t offset = start - mr_.start; offset < stopper; offset +=1)
@ -46,6 +69,7 @@ class SegmentFinder
template <class needleType, class hayType, typename comparator >
bool Filter (needleType needle, vector <uint64_t> &found, vector <uint64_t> &newfound, comparator oper)
{
if(!valid) return !newfound.empty();
for( uint64_t i = 0; i < found.size(); i++)
{
if(mr_.isInRange(found[i]))
@ -62,6 +86,7 @@ class SegmentFinder
SegmentedFinder * _SF;
DFHack::Context * _DF;
DFHack::t_memrange mr_;
bool valid;
};
class SegmentedFinder
@ -286,15 +311,207 @@ bool vectorAll (SegmentedFinder* s, vecTriplet *x, int )
return false;
}
struct Bytestream
class Bytestreamdata
{
uint32_t length;
void * object;
public:
void * object;
uint32_t length;
uint32_t allocated;
uint32_t n_used;
};
class Bytestream
{
public:
Bytestream(void * obj, uint32_t len, bool alloc = false)
{
d = new Bytestreamdata();
d->allocated = alloc;
d->object = obj;
d->length = len;
d->n_used = 1;
constant = false;
}
Bytestream()
{
d = new Bytestreamdata();
d->allocated = false;
d->object = 0;
d->length = 0;
d->n_used = 1;
constant = false;
}
Bytestream( Bytestream & bs)
{
d =bs.d;
d->n_used++;
constant = false;
}
Bytestream( const Bytestream & bs)
{
d =bs.d;
d->n_used++;
constant = true;
}
~Bytestream()
{
d->n_used --;
if(d->allocated && d->object && d->n_used == 0)
{
free (d->object);
free (d);
}
}
bool Allocate(size_t bytes)
{
if(constant)
return false;
if(d->allocated)
{
d->object = realloc(d->object, bytes);
}
else
{
d->object = malloc( bytes );
}
if(d->object)
{
d->allocated = bytes;
return true;
}
else
{
d->allocated = 0;
return false;
}
}
template < class T >
bool insert( T what )
{
if(constant)
return false;
if(d->length+sizeof(T) >= d->allocated)
Allocate((d->length+sizeof(T)) * 2);
(*(T *)( (uint64_t)d->object + d->length)) = what;
d->length += sizeof(T);
return true;
}
Bytestreamdata * d;
bool constant;
};
std::ostream& operator<< ( std::ostream& out, Bytestream& bs )
{
if(bs.d->object)
{
out << "bytestream " << dec << bs.d->length << "/" << bs.d->allocated << " bytes" << endl;
for(int i = 0; i < bs.d->length; i++)
{
out << hex << (int) ((uint8_t *) bs.d->object)[i] << " ";
}
out << endl;
}
else
{
out << "empty bytestresm" << endl;
}
return out;
}
std::istream& operator>> ( std::istream& out, Bytestream& bs )
{
string read;
while(!out.eof())
{
string tmp;
out >> tmp;
read.append(tmp);
}
cout << read << endl;
bs.d->length = 0;
size_t first = read.find_first_of("\"");
size_t last = read.find_last_of("\"");
size_t start = first + 1;
if(first == read.npos)
{
std::transform(read.begin(), read.end(), read.begin(), (int(*)(int)) tolower);
bs.Allocate(read.size()); // overkill. size / 2 should be good, but this is safe
int state = 0;
char big = 0;
char small = 0;
string::iterator it = read.begin();
// iterate through string, construct a bytestream out of 00-FF bytes
while(it != read.end())
{
char reads = *it;
if((reads >='0' && reads <= '9'))
{
if(state == 0)
{
big = reads - '0';
state = 1;
}
else if(state == 1)
{
small = reads - '0';
state = 0;
bs.insert<char>(big*16 + small);
}
}
if((reads >= 'a' && reads <= 'f'))
{
if(state == 0)
{
big = reads - 'a' + 10;
state = 1;
}
else if(state == 1)
{
small = reads - 'a' + 10;
state = 0;
bs.insert<char>(big*16 + small);
}
}
it++;
}
// we end in state= 1. should we add or should we trim... or throw errors?
// I decided on adding
if (state == 1)
{
small = 0;
bs.insert<char>(big*16 + small);
}
}
else
{
if(last == first)
{
// only one "
last = read.size();
}
size_t length = last - start;
// construct bytestream out of stuff between ""
bs.d->length = length;
if(length)
{
// todo: Bytestream should be able to handle this without external code
bs.Allocate(length);
bs.d->length = length;
const char* strstart = read.c_str();
memcpy(bs.d->object, strstart + start, length);
}
else
{
bs.d->object = 0;
}
}
cout << bs;
return out;
}
bool findBytestream (SegmentedFinder* s, void *addr, Bytestream compare )
{
if(memcmp(addr, compare.object, compare.length) == 0)
if(memcmp(addr, compare.d->object, compare.d->length) == 0)
return true;
return false;
}

@ -0,0 +1,782 @@
// this is an incremental search tool. It only works on Linux.
// here be dragons... and ugly code :P
#include <iostream>
#include <climits>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
#ifndef LINUX_BUILD
#define WINVER 0x0500
// this one prevents windows from infecting the global namespace with filth
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <DFHack.h>
#include "SegmentedFinder.h"
class Token
{
public:
Token(uint64_t _offset)
{
offset = _offset;
offset_valid = 1;
value_valid = 0;
parent = 0;
}
Token(const std::string & offsetn)
{
full_offset_name = offsetn;
offset_valid = 0;
value_valid = 0;
parent = 0;
}
Token()
{
offset_valid = 0;
value_valid = 0;
parent = 0;
}
virtual ~Token(){};
virtual bool LoadData(SegmentedFinder * s) = 0;
virtual void EmptyData()
{
value_valid = false;
};
virtual bool Match(SegmentedFinder * s, uint64_t offset) = 0;
virtual void EmptyOffset()
{
offset_valid = false;
};
virtual bool AcquireOffset(DFHack::VersionInfo * vinfo)
{
vinfo->getOffset(full_offset_name);
return true;
}
virtual uint32_t Length() = 0;
virtual uint64_t getAbsolute(){if(parent) return parent->getAbsolute() + offset; else return offset;};
void setParent( Token *par )
{
par = parent;
}
protected:
uint64_t offset;// offset from the start of the parent token
std::string full_offset_name;
Token * parent;
bool offset_valid :1;
bool value_valid :1;
};
class Byte: virtual public Token
{
public:
Byte(uint64_t _offset):Token(_offset){};
Byte():Token(){};
~Byte();
virtual bool LoadData(SegmentedFinder * s)
{
if(offset_valid)
{
char * ptr = s->Translate<char>(getAbsolute());
if(ptr)
{
value = *ptr;
value_valid = true;
return true;
}
}
return false;
};
// is the loaded data same as data at offset? yes -> set our offset to that.
virtual bool Match(SegmentedFinder * s, uint64_t offs)
{
if(value_valid && (*s->Translate<char>(parent->getAbsolute() + offset)) == value )
{
if(parent)
offset = offs - parent->getAbsolute();
else
offset = offs;
return true;
}
return false;
};
virtual uint32_t Length()
{
return 1;
};
private:
char value;
};
class Short: virtual public Token
{
public:
Short(uint64_t _offset):Token(_offset){};
Short():Token(){};
~Short();
virtual bool LoadData(SegmentedFinder * s)
{
if(offset_valid)
{
uint16_t * ptr = s->Translate<uint16_t>(getAbsolute());
if(ptr)
{
value = *ptr;
value_valid = true;
return true;
}
}
return false;
};
// is the loaded data same as data at offset? yes -> set our offset to that.
virtual bool Match(SegmentedFinder * s, uint64_t offs)
{
if(value_valid && (*s->Translate<uint16_t>(parent->getAbsolute() + offset)) == value )
{
if(parent)
offset = offs - parent->getAbsolute();
else
offset = offs;
return true;
}
return false;
};
virtual uint32_t Length()
{
return 2;
};
private:
uint16_t value;
};
class Long: virtual public Token
{
public:
Long(uint64_t _offset):Token(_offset){};
Long():Token(){};
~Long();
virtual bool LoadData(SegmentedFinder * s)
{
if(offset_valid)
{
uint32_t * ptr = s->Translate<uint32_t>(getAbsolute());
if(ptr)
{
value = *ptr;
value_valid = true;
return true;
}
}
return false;
};
// is the loaded data same as data at offset? yes -> set our offset to that.
virtual bool Match(SegmentedFinder * s, uint64_t offs)
{
if(value_valid && (*s->Translate<uint32_t>(offs)) == value )
{
if(parent)
offset = offs - parent->getAbsolute();
else
offset = offs;
return true;
}
return false;
};
virtual uint32_t Length(){return 4;};
private:
uint32_t value;
};
class PtrVector : virtual public Token
{
public:
PtrVector(uint64_t _offset):Token(_offset){};
PtrVector():Token(){};
~PtrVector();
virtual uint32_t Length(){return 12;};
private:
vector <uint64_t> value;
};
class Pointer: virtual public Token
{
public:
Pointer(uint64_t _offset):Token(_offset){};
Pointer():Token(){};
~Pointer();
virtual uint32_t Length(){return 4;};
private:
uint64_t value;
};
class String: virtual public Token
{
protected:
string value;
};
class Struct: virtual public Token
{
public:
Struct(uint64_t _offset):Token(_offset){};
Struct():Token(){};
~Struct(){};
void Add( Token * t ){members.push_back(t);};
virtual uint32_t Length(){return 0;}; // FIXME: temporary solution, should be the minimal length of all the contents combined
virtual bool LoadData(SegmentedFinder* s)
{
bool OK = true;
for(int i = 0; i < members.size() && OK; i++)
OK &= members[i]->LoadData(s);
return OK;
};
// TODO: IMPLEMENT!
virtual bool Match(SegmentedFinder* s, uint64_t offset)
{
return false;
}
private:
vector<Token*> members;
};
class LinuxString: virtual public String
{
public:
LinuxString(uint64_t _offset):Token(_offset){};
LinuxString():Token(){};
~LinuxString(){};
virtual uint32_t Length(){return 4;};
virtual bool LoadData(SegmentedFinder* s)
{
return false;
}
virtual bool Match(SegmentedFinder* s, uint64_t offset)
{
return false;
}
/*
// read string pointer, translate to local scheme
char *str = sf->Translate<char>(*offset);
// verify
if(!str)
return false;
uint32_t length = *(uint32_t *)(offset - 12);
uint32_t capacity = *(uint32_t *)(offset - 8);
if(length > capacity)
return false;
//char * temp = new char[length+1];
// read data from inside the string structure
//memcpy(temp, str,length + 1);
output = str;
return true;
*/
};
class WindowsString: virtual public String
{
public:
WindowsString(uint64_t _offset):Token(_offset){};
WindowsString():Token(){};
~WindowsString(){};
virtual uint32_t Length(){return 0x1C;}; // FIXME: pouzivat Memory.xml?
virtual bool LoadData(SegmentedFinder* s)
{
return false;
}
virtual bool Match(SegmentedFinder* s, uint64_t offset)
{
return false;
}
string rdWinString( char * offset, SegmentedFinder & sf )
{
char * start_offset = offset + 4; // FIXME: pouzivat Memory.xml?
uint32_t length = *(uint32_t *)(offset + 20); // FIXME: pouzivat Memory.xml?
uint32_t capacity = *(uint32_t *)(offset + 24); // FIXME: pouzivat Memory.xml?
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
memcpy(temp, start_offset,capacity);
//read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = sf.Translate<char>(*(uint32_t*)start_offset);
memcpy(temp, start_offset,capacity);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}
};
inline void printRange(DFHack::t_memrange * tpr)
{
std::cout << std::hex << tpr->start << " - " << tpr->end << "|" << (tpr->read ? "r" : "-") << (tpr->write ? "w" : "-") << (tpr->execute ? "x" : "-") << "|" << tpr->name << std::endl;
}
bool getRanges(DFHack::Process * p, vector <DFHack::t_memrange>& selected_ranges)
{
vector <DFHack::t_memrange> ranges;
selected_ranges.clear();
p->getMemRanges(ranges);
cout << "Which range to search? (default is 1-4)" << endl;
for(int i = 0; i< ranges.size();i++)
{
cout << dec << "(" << i << ") ";
printRange(&(ranges[i]));
}
int start, end;
while(1)
{
string select;
cout << ">>";
std::getline(cin, select);
if(select.empty())
{
// empty input, assume default. observe the length of the memory range vector
// these are hardcoded values, intended for my convenience only
if(p->getDescriptor()->getOS() == DFHack::OS_WINDOWS)
{
start = min(11, (int)ranges.size());
end = min(14, (int)ranges.size());
}
else if(p->getDescriptor()->getOS() == DFHack::OS_LINUX)
{
start = min(2, (int)ranges.size());
end = min(4, (int)ranges.size());
}
else
{
start = 1;
end = 1;
}
break;
}
// I like the C variants here. much less object clutter
else if(sscanf(select.c_str(), "%d-%d", &start, &end) == 2)
{
start = min(start, (int)ranges.size());
end = min(end, (int)ranges.size());
break;
}
else
{
continue;
}
break;
}
end++;
cout << "selected ranges:" <<endl;
vector <DFHack::t_memrange>::iterator it;
it = ranges.begin() + start;
while (it != ranges.begin() + end)
{
// check if readable
if((*it).read)
{
selected_ranges.push_back(*it);
printRange(&*it);
}
it++;
}
return true;
}
bool getNumber (string prompt, int & output, int def, bool pdef = true)
{
cout << prompt;
if(pdef)
cout << " default=" << def << endl;
while (1)
{
string select;
cout << ">>";
std::getline(cin, select);
if(select.empty())
{
output = def;
break;
}
else if( sscanf(select.c_str(), "%d", &output) == 1 )
{
break;
}
else
{
continue;
}
}
return true;
}
bool getString (string prompt, string & output)
{
cout << prompt;
cout << ">>";
string select;
std::getline(cin, select);
if(select.empty())
{
return false;
}
else
{
output = select;
return true;
}
}
// meh
#pragma pack(1)
struct tilecolors
{
uint16_t fore;
uint16_t back;
uint16_t bright;
};
#pragma pack()
void printFound(vector <uint64_t> &found, const char * what)
{
cout << what << ":" << endl;
for(int i = 0; i < found.size();i++)
{
cout << hex << "0x" << found[i] << endl;
}
}
void printFoundStrVec(vector <uint64_t> &found, const char * what, SegmentedFinder & s)
{
cout << what << ":" << endl;
for(int i = 0; i < found.size();i++)
{
cout << hex << "0x" << found[i] << endl;
cout << "--------------------------" << endl;
vecTriplet * vt = s.Translate<vecTriplet>(found[i]);
if(vt)
{
int j = 0;
for(uint32_t idx = vt->start; idx < vt->finish; idx += sizeof(uint32_t))
{
uint32_t object_ptr;
// deref ptr idx, get ptr to object
if(!s.Read(idx,object_ptr))
{
cout << "BAD!" << endl;
break;
}
// deref ptr to first object, get ptr to string
uint32_t string_ptr;
if(!s.Read(object_ptr,string_ptr))
{
cout << "BAD!" << endl;
break;
}
// get string location in our local cache
char * str = s.Translate<char>(string_ptr);
if(!str)
{
cout << "BAD!" << endl;
break;
}
cout << dec << j << ":" << hex << "0x" << object_ptr << " : " << str << endl;
j++;
}
}
else
{
cout << "BAD!" << endl;
break;
}
cout << "--------------------------" << endl;
}
}
class TokenFactory
{
DFHack::OSType platform;
public:
TokenFactory(DFHack::OSType platform_in)
{
platform = platform_in;
}
template <class T>
T * Build()
{
return new T;
}
template <class T>
T * Build(uint64_t offset)
{
return new T(offset);
}
};
template <>
String * TokenFactory::Build()
{
switch(platform)
{
case DFHack::OS_WINDOWS:
return new WindowsString();
case DFHack::OS_LINUX:
case DFHack::OS_APPLE:
return new LinuxString();
}
return 0;
};
template <>
String * TokenFactory::Build(uint64_t offset)
{
switch(platform)
{
case DFHack::OS_WINDOWS:
return new WindowsString(offset);
case DFHack::OS_LINUX:
case DFHack::OS_APPLE:
return new LinuxString(offset);
}
return 0;
};
void autoSearch(DFHack::Context * DF, vector <DFHack::t_memrange>& ranges, DFHack::OSType platform)
{
cout << "stealing memory..." << endl;
SegmentedFinder sf(ranges, DF);
TokenFactory tf(platform);
cout << "done!" << endl;
Struct maps;
maps.Add(tf.Build<String>());
maps.Add(tf.Build<String>());
/*
vector <uint64_t> allVectors;
vector <uint64_t> filtVectors;
vector <uint64_t> to_filter;
cout << "stealing memory..." << endl;
SegmentedFinder sf(ranges, DF);
cout << "looking for vectors..." << endl;
sf.Find<int ,vecTriplet>(0,4,allVectors, vectorAll);
filtVectors = allVectors;
cout << "-------------------" << endl;
cout << "!!LANGUAGE TABLES!!" << endl;
cout << "-------------------" << endl;
uint64_t kulet_vector;
uint64_t word_table_offset;
uint64_t DWARF_vector;
uint64_t DWARF_object;
// find lang vector (neutral word table)
to_filter = filtVectors;
sf.Filter<const char * ,vecTriplet>("ABBEY",to_filter, vectorStringFirst);
uint64_t lang_addr = to_filter[0];
// find dwarven language word table
to_filter = filtVectors;
sf.Filter<const char * ,vecTriplet>("kulet",to_filter, vectorStringFirst);
kulet_vector = to_filter[0];
// find vector of languages
to_filter = filtVectors;
sf.Filter<const char * ,vecTriplet>("DWARF",to_filter, vectorStringFirst);
// verify
for(int i = 0; i < to_filter.size(); i++)
{
vecTriplet * vec = sf.Translate<vecTriplet>(to_filter[i]);
if(((vec->finish - vec->start) / 4) == 4) // verified
{
DWARF_vector = to_filter[i];
DWARF_object = sf.Read<uint32_t>(vec->start);
// compute word table offset from dwarf word table and dwarf language object addresses
word_table_offset = kulet_vector - DWARF_object;
break;
}
}
cout << "translation vector: " << hex << "0x" << DWARF_vector << endl;
cout << "lang vector: " << hex << "0x" << lang_addr << endl;
cout << "word table offset: " << hex << "0x" << word_table_offset << endl;
cout << "-------------" << endl;
cout << "!!MATERIALS!!" << endl;
cout << "-------------" << endl;
// inorganics vector
to_filter = filtVectors;
//sf.Find<uint32_t,vecTriplet>(257 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("IRON",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("ONYX",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("RAW_ADAMANTINE",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("BLOODSTONE",to_filter, vectorString);
printFound(to_filter,"inorganics");
// organics vector
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(52 * 4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst);
printFound(to_filter,"organics");
// tree vector
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(31 * 4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("MANGROVE",to_filter, vectorStringFirst);
printFound(to_filter,"trees");
// plant vector
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(21 * 4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst);
printFound(to_filter,"plants");
// color descriptors
//AMBER, 112
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(112 * 4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("AMBER",to_filter, vectorStringFirst);
printFound(to_filter,"color descriptors");
if(!to_filter.empty())
{
uint64_t vec = to_filter[0];
vecTriplet *vtColors = sf.Translate<vecTriplet>(vec);
uint32_t colorObj = sf.Read<uint32_t>(vtColors->start);
cout << "Amber color:" << hex << "0x" << colorObj << endl;
// TODO: find string 'amber', the floats
}
// all descriptors
//AMBER, 338
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(338 * 4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("AMBER",to_filter, vectorStringFirst);
printFound(to_filter,"all descriptors");
// creature type
//ELEPHANT, ?? (demons abound)
to_filter = filtVectors;
//sf.Find<uint32_t,vecTriplet>(338 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Filter<const char * ,vecTriplet>("ELEPHANT",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("CAT",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("DWARF",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("WAMBLER_FLUFFY",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("TOAD",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("DEMON_1",to_filter, vectorString);
vector <uint64_t> toad_first = to_filter;
vector <uint64_t> elephant_first = to_filter;
sf.Filter<const char * ,vecTriplet>("TOAD",toad_first, vectorStringFirst);
sf.Filter<const char * ,vecTriplet>("ELEPHANT",elephant_first, vectorStringFirst);
printFoundStrVec(toad_first,"toad-first creature types",sf);
printFound(elephant_first,"elephant-first creature types");
printFound(to_filter,"all creature types");
uint64_t to_use = 0;
if(!elephant_first.empty())
{
to_use = elephant_first[0];
vecTriplet *vtCretypes = sf.Translate<vecTriplet>(to_use);
uint32_t elephant = sf.Read<uint32_t>(vtCretypes->start);
uint64_t Eoffset;
cout << "Elephant: 0x" << hex << elephant << endl;
cout << "Elephant: rawname = 0x0" << endl;
uint8_t letter_E = 'E';
Eoffset = sf.FindInRange<uint8_t,uint8_t> (letter_E,equalityP<uint8_t>, elephant, 0x300 );
if(Eoffset)
{
cout << "Elephant: big E = 0x" << hex << Eoffset - elephant << endl;
}
Eoffset = sf.FindInRange<const char *,vecTriplet> ("FEMALE",vectorStringFirst, elephant, 0x300 );
if(Eoffset)
{
cout << "Elephant: caste vector = 0x" << hex << Eoffset - elephant << endl;
}
Eoffset = sf.FindInRange<const char *,vecTriplet> ("SKIN",vectorStringFirst, elephant, 0x2000 );
if(Eoffset)
{
cout << "Elephant: extract? vector = 0x" << hex << Eoffset - elephant << endl;
}
tilecolors eletc = {7,0,0};
Bytestream bs_eletc(&eletc, sizeof(tilecolors));
cout << bs_eletc;
Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_eletc, findBytestream, elephant, 0x300 );
if(Eoffset)
{
cout << "Elephant: colors = 0x" << hex << Eoffset - elephant << endl;
}
//cout << "Amber color:" << hex << "0x" << colorObj << endl;
// TODO: find string 'amber', the floats
}
if(!toad_first.empty())
{
to_use = toad_first[0];
vecTriplet *vtCretypes = sf.Translate<vecTriplet>(to_use);
uint32_t toad = sf.Read<uint32_t>(vtCretypes->start);
uint64_t Eoffset;
cout << "Toad: 0x" << hex << toad << endl;
cout << "Toad: rawname = 0x0" << endl;
Eoffset = sf.FindInRange<uint8_t,uint8_t> (0xF9,equalityP<uint8_t>, toad, 0x300 );
if(Eoffset)
{
cout << "Toad: character (not reliable) = 0x" << hex << Eoffset - toad << endl;
}
Eoffset = sf.FindInRange<const char *,vecTriplet> ("FEMALE",vectorStringFirst, toad, 0x300 );
if(Eoffset)
{
cout << "Toad: caste vector = 0x" << hex << Eoffset - toad << endl;
}
Eoffset = sf.FindInRange<const char *,vecTriplet> ("SKIN",vectorStringFirst, toad, 0x2000 );
if(Eoffset)
{
cout << "Toad: extract? vector = 0x" << hex << Eoffset - toad << endl;
}
tilecolors toadtc = {2,0,0};
Bytestream bs_toadc(&toadtc, sizeof(tilecolors));
Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_toadc, findBytestream, toad, 0x300 );
if(Eoffset)
{
cout << "Toad: colors = 0x" << hex << Eoffset - toad << endl;
}
}*/
}
int main (void)
{
string select;
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context * DF = DFMgr.getSingleContext();
try
{
DF->Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::Process * p = DF->getProcess();
vector <DFHack::t_memrange> selected_ranges;
getRanges(p,selected_ranges);
DFHack::VersionInfo *minfo = DF->getMemoryInfo();
autoSearch(DF,selected_ranges, minfo->getOS());
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}

@ -8,13 +8,24 @@ using namespace std;
#include <DFHack.h>
int main (void)
int main (int argc, char** argv)
{
bool quiet = false;
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-q")
{
quiet = true;
}
}
uint32_t x_max,y_max,z_max;
uint32_t num_blocks = 0;
uint32_t bytes_read = 0;
vector<DFHack::t_spattervein> splatter;
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF = DFMgr.getSingleContext();
try
@ -30,7 +41,7 @@ int main (void)
return 1;
}
DFHack::Maps *Mapz = DF->getMaps();
// init the map
if(!Mapz->Start())
{
@ -40,11 +51,12 @@ int main (void)
#endif
return 1;
}
Mapz->getSize(x_max,y_max,z_max);
uint8_t zeroes [16][16] = {0};
DFHack::occupancies40d occ;
// walk the map
for(uint32_t x = 0; x< x_max;x++)
{
@ -55,10 +67,18 @@ int main (void)
if(Mapz->isValidBlock(x,y,z))
{
Mapz->ReadVeins(x,y,z,0,0,&splatter);
Mapz->ReadOccupancy(x,y,z,&occ);
for(int i = 0; i < 16; i++)
for(int j = 0; j < 16; j++)
{
occ[i][j].unibits.splatter = 0;
}
Mapz->WriteOccupancy(x,y,z,&occ);
for(uint32_t i = 0; i < splatter.size(); i++)
{
DFHack::t_spattervein & vein = splatter[i];
if(vein.mat1 != 0xC)
// filter away snow and mud
if(vein.mat1 != 0xC && vein.mat1 != 0x6)
{
uint32_t addr = vein.address_of;
uint32_t offset = offsetof(DFHack::t_spattervein, intensity);
@ -71,8 +91,11 @@ int main (void)
}
DF->Detach();
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
if (!quiet)
{
cout << "Done. Press any key to continue" << endl;
cin.ignore();
}
#endif
return 0;
}

@ -39,7 +39,7 @@ int main ()
{
item_vec_offset = p->getDescriptor()->getAddress ("items_vector");
}
catch(DFHack::Error::MissingMemoryDefinition & e)
catch(DFHack::Error::AllMemdef & e)
{
cerr << "missing offset for the item vector, exiting :(" << endl;
#ifndef LINUX_BUILD

@ -0,0 +1,49 @@
// This forces the game to pause.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
#include <DFHack.h>
#include <dfhack/modules/Gui.h>
int main (int argc, char** argv)
{
bool quiet = false;
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-q")
{
quiet = true;
}
}
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF;
try
{
DF = DFMgr.getSingleContext();
DF->Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
if(!quiet) cin.ignore();
#endif
return 1;
}
DFHack::Gui *Gui =DF->getGui();
cout << "Pausing..." << endl;
Gui->SetPauseState(true);
DF->Resume();
#ifndef LINUX_BUILD
cout << "Done. The current game frame will have to finish first. This can take some time on bugged maps." << endl;
if (!quiet) cin.ignore();
#endif
return 0;
}

@ -4,6 +4,7 @@
#include <climits>
#include <vector>
#include <map>
#include <set>
#include <ctime>
#include <string.h>
#include <stdio.h>
@ -20,146 +21,12 @@ using namespace std;
#include <DFHack.h>
#include "SegmentedFinder.h"
template <class T>
class holder
{
public:
vector <T> values;
SegmentedFinder & sf;
holder(SegmentedFinder& sff):sf(sff){};
bool isValid(size_t idx)
{
};
};
class address
{
public:
uint64_t addr_;
unsigned int valid : 1;
virtual void print(SegmentedFinder& sff)
{
cout << hex << "0x" << addr_ << endl;
};
address(const uint64_t addr)
{
addr_ = addr;
valid = false;
}
virtual address & operator=(const uint64_t in)
{
addr_ = in;
valid = false;
return *this;
}
virtual bool isValid(SegmentedFinder& sff)
{
if(valid) return true;
if(sff.getSegmentForAddress(addr_))
{
valid = 1;
}
}
virtual bool equals (SegmentedFinder & sf, address & rhs)
{
return rhs.addr_ == addr_;
}
};
// pointer to a null-terminated byte string
class Cstr: public address
{
void print(SegmentedFinder & sf)
{
cout << hex << "0x" << addr_ << ": \"" << sf.Translate<char>(addr_) << "\"" << endl;
}
bool equals(SegmentedFinder & sf,const char * rhs)
{
uint32_t addr2 = *(sf.Translate<uint32_t>(addr_));
return strcmp(sf.Translate<const char>(addr2), rhs) == 0;
}
template <class Predicate, class inType>
bool equalsP(SegmentedFinder & sf,inType rhs)
{
return Predicate(addr_, sf, rhs);
}
bool isValid(SegmentedFinder& sf)
{
if (address::isValid(sf))
{
// read the pointer
uint32_t addr2 = *(sf.Translate<uint32_t>(addr_));
// is it a real pointer? a pretty weak test, but whatever.
if(sf.getSegmentForAddress(addr2))
return true;
}
return false;
}
};
// STL STRING
#ifdef LINUX_BUILD
class STLstr: public address
{
};
#endif
#ifndef LINUX_BUILD
class STLstr: public address
{
};
#endif
// STL VECTOR
#ifdef LINUX_BUILD
class Vector: public address
{
};
#endif
#ifndef LINUX_BUILD
class Vector: public address
{
};
#endif
class Int64: public address{};
class Int32: public address{};
class Int16: public address{};
class Int8: public address{};
inline void printRange(DFHack::t_memrange * tpr)
{
std::cout << std::hex << tpr->start << " - " << tpr->end << "|" << (tpr->read ? "r" : "-") << (tpr->write ? "w" : "-") << (tpr->execute ? "x" : "-") << "|" << tpr->name << std::endl;
}
string rdWinString( char * offset, SegmentedFinder & sf )
{
char * start_offset = offset + 4;
uint32_t length = *(uint32_t *)(offset + 20);
uint32_t capacity = *(uint32_t *)(offset + 24);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
memcpy(temp, start_offset,capacity);
//read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = sf.Translate<char>(*(uint32_t*)start_offset);
memcpy(temp, start_offset,capacity);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}
bool getRanges(DFHack::Process * p, vector <DFHack::t_memrange>& selected_ranges)
{
vector <DFHack::t_memrange> ranges;
@ -181,12 +48,12 @@ bool getRanges(DFHack::Process * p, vector <DFHack::t_memrange>& selected_ranges
{
// empty input, assume default. observe the length of the memory range vector
// these are hardcoded values, intended for my convenience only
if(p->getDescriptor()->getOS() == DFHack::VersionInfo::OS_WINDOWS)
if(p->getDescriptor()->getOS() == DFHack::OS_WINDOWS)
{
start = min(11, (int)ranges.size());
end = min(14, (int)ranges.size());
}
else if(p->getDescriptor()->getOS() == DFHack::VersionInfo::OS_LINUX)
else if(p->getDescriptor()->getOS() == DFHack::OS_LINUX)
{
start = min(2, (int)ranges.size());
end = min(4, (int)ranges.size());
@ -225,6 +92,7 @@ bool getRanges(DFHack::Process * p, vector <DFHack::t_memrange>& selected_ranges
}
it++;
}
return true;
}
bool getNumber (string prompt, int & output, int def, bool pdef = true)
@ -273,7 +141,7 @@ bool getString (string prompt, string & output)
template <class T>
bool Incremental ( vector <uint64_t> &found, const char * what, T& output,
const char *singular = "address", const char *plural = "addresses" )
const char *singular = "address", const char *plural = "addresses", bool numberz = false )
{
string select;
if(found.empty())
@ -311,26 +179,33 @@ bool Incremental ( vector <uint64_t> &found, const char * what, T& output,
}
goto incremental_more;
}
else if(select.empty())
else if(select == "q")
{
return false;
}
else if(select.empty())
{
goto incremental_more;
}
else
{
if( sscanf(select.c_str(),"0x%x", &output) == 1 )
if(numberz)
{
//cout << dec << output << endl;
return true;
}
if( sscanf(select.c_str(),"%d", &output) == 1 )
{
//cout << dec << output << endl;
return true;
if( sscanf(select.c_str(),"0x%x", &output) == 1 )
{
//cout << dec << output << endl;
return true;
}
if( sscanf(select.c_str(),"%d", &output) == 1 )
{
//cout << dec << output << endl;
return true;
}
}
stringstream ss (stringstream::in | stringstream::out);
ss << select;
ss >> output;
cout << output;
if(!ss.fail())
{
return true;
@ -358,7 +233,7 @@ void FindIntegers(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& r
uint32_t test1;
vector <uint64_t> found;
found.reserve(100);
while(Incremental(found, "integer",test1))
while(Incremental(found, "integer",test1,"address", "addresses",true))
{
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
@ -514,6 +389,220 @@ void FindStrings(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ra
}
}
void FindData(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
vector <uint64_t> found;
Bytestream select;
while (Incremental(found,"byte stream",select,"byte stream","byte streams"))
{
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream);
DF->Detach();
}
}
bool TriggerIncremental ( vector <uint64_t> &found )
{
string select;
if(found.empty())
{
cout << "search ready - position the DF cursor and hit enter when ready" << endl;
}
else if( found.size() == 1 )
{
cout << "Found single coord!" << endl;
cout << hex << "0x" << found[0] << endl;
}
else
{
cout << "Found " << dec << found.size() << " coords." << endl;
}
incremental_more:
cout << ">>";
std::getline(cin, select);
size_t num = 0;
if( sscanf(select.c_str(),"p %d", &num) && num > 0)
{
cout << "Found coords:" << endl;
for(int i = 0; i < min(found.size(), num);i++)
{
cout << hex << "0x" << found[i] << endl;
}
goto incremental_more;
}
else if(select == "p")
{
cout << "Found coords:" << endl;
for(int i = 0; i < found.size();i++)
{
cout << hex << "0x" << found[i] << endl;
}
goto incremental_more;
}
else if(select == "q")
{
return false;
}
else return true;
}
void FindCoords(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
vector <uint64_t> found;
int size = 4;
do
{
getNumber("Select coord size (2,4 bytes)",size, 4);
} while (size != 2 && size != 4);
while (TriggerIncremental(found))
{
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
DFHack::Position * pos = DF->getPosition();
pos->Start();
int32_t x, y, z;
pos->getCursorCoords(x,y,z);
cout << "Searching for: " << dec << x << ":" << y << ":" << z << endl;
Bytestream select;
if(size == 2)
{
select.insert<uint16_t>(x);
select.insert<uint16_t>(y);
select.insert<uint16_t>(z);
}
else
{
select.insert<uint32_t>(x);
select.insert<uint32_t>(y);
select.insert<uint32_t>(z);
}
cout << select << endl;
SegmentedFinder sf(ranges,DF);
sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream);
DF->Detach();
}
}
void PtrTrace(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
int element_size;
do
{
getNumber("Set search granularity",element_size, 4);
} while (element_size < 1);
vector <uint64_t> found;
set <uint64_t> check; // to detect circles
uint32_t select;
while (Incremental(found,"address",select,"addresses","addresses",true))
{
DFMgr.Refresh();
found.clear();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
cout <<"Starting: 0x" << hex << select << endl;
while(sf.getSegmentForAddress(select))
{
sf.Incremental<uint32_t,uint32_t>(select,element_size,found, equalityP<uint32_t>);
if(found.empty())
{
cout << ".";
cout.flush();
select -=element_size;
continue;
}
cout << endl;
cout <<"Object start: 0x" << hex << select << endl;
cout <<"Pointer: 0x" << hex << found[0] << endl;
// make sure we don't go in circles'
if(check.count(select))
{
break;
}
check.insert(select);
// ascend
select = found[0];
found.clear();
}
DF->Detach();
}
}
/*
{
vector <uint64_t> found;
Bytestream select;
while (Incremental(found,"byte stream",select,"byte stream","byte streams"))
{
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream);
DF->Detach();
}
}
*/
void DataPtrTrace(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
int element_size;
do
{
getNumber("Set search granularity",element_size, 4);
} while (element_size < 1);
vector <uint64_t> found;
set <uint64_t> check; // to detect circles
uint32_t select;
Bytestream bs_select;
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
DFMgr.Refresh();
found.clear();
SegmentedFinder sf(ranges,DF);
while(found.empty())
{
Incremental(found,"byte stream",bs_select,"byte stream","byte streams");
sf.Incremental< Bytestream ,uint32_t>(bs_select,1,found, findBytestream);
}
select = found[0];
cout <<"Starting: 0x" << hex << select << endl;
while(sf.getSegmentForAddress(select))
{
sf.Incremental<uint32_t,uint32_t>(select,element_size,found, equalityP<uint32_t>);
if(found.empty())
{
cout << ".";
cout.flush();
select -=element_size;
continue;
}
cout << endl;
cout <<"Object start: 0x" << hex << select << endl;
cout <<"Pointer: 0x" << hex << found[0] << endl;
// make sure we don't go in circles'
if(check.count(select))
{
break;
}
check.insert(select);
// ascend
select = found[0];
found.clear();
}
DF->Detach();
}
void printFound(vector <uint64_t> &found, const char * what)
{
cout << what << ":" << endl;
@ -580,7 +669,7 @@ struct tilecolors
};
#pragma pack()
void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& ranges)
void autoSearch(DFHack::Context * DF, vector <DFHack::t_memrange>& ranges)
{
vector <uint64_t> allVectors;
vector <uint64_t> filtVectors;
@ -664,6 +753,15 @@ void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& rang
sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst);
printFound(to_filter,"organics");
// new organics vector
to_filter = filtVectors;
sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("MEADOW-GRASS",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("TUNNEL_TUBE",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("WEED_BLADE",to_filter, vectorString);
sf.Filter<const char * ,vecTriplet>("EYEBALL",to_filter, vectorString);
printFound(to_filter,"organics 31.19");
// tree vector
to_filter = filtVectors;
sf.Filter<uint32_t,vecTriplet>(31 * 4,to_filter,vectorLength<uint32_t>);
@ -726,7 +824,8 @@ void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& rang
uint64_t Eoffset;
cout << "Elephant: 0x" << hex << elephant << endl;
cout << "Elephant: rawname = 0x0" << endl;
Eoffset = sf.FindInRange<uint8_t,uint8_t> ('E',equalityP<uint8_t>, elephant, 0x300 );
uint8_t letter_E = 'E';
Eoffset = sf.FindInRange<uint8_t,uint8_t> (letter_E,equalityP<uint8_t>, elephant, 0x300 );
if(Eoffset)
{
cout << "Elephant: big E = 0x" << hex << Eoffset - elephant << endl;
@ -742,7 +841,8 @@ void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& rang
cout << "Elephant: extract? vector = 0x" << hex << Eoffset - elephant << endl;
}
tilecolors eletc = {7,0,0};
Bytestream bs_eletc = {sizeof(tilecolors), &eletc};
Bytestream bs_eletc(&eletc, sizeof(tilecolors));
cout << bs_eletc;
Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_eletc, findBytestream, elephant, 0x300 );
if(Eoffset)
{
@ -775,7 +875,7 @@ void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& rang
cout << "Toad: extract? vector = 0x" << hex << Eoffset - toad << endl;
}
tilecolors toadtc = {2,0,0};
Bytestream bs_toadc = {sizeof(tilecolors), &toadtc};
Bytestream bs_toadc(&toadtc, sizeof(tilecolors));
Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_toadc, findBytestream, toad, 0x300 );
if(Eoffset)
{
@ -810,58 +910,80 @@ int main (void)
getRanges(p,selected_ranges);
DFHack::VersionInfo *minfo = DF->getMemoryInfo();
DFHack::VersionInfo::OSType os = minfo->getOS();
DFHack::OSType os = minfo->getOS();
string prompt =
"Select search type: 1=number(default), 2=vector by length, 3=vector>object>string,\n"
" 4=string, 5=automated offset search, 6=vector by address in its array,\n"
" 7=pointer vector by address of an object, 8=vector>first object>string\n"
" 9=string buffers\n";
" 9=string buffers, 10=known data, 11=backpointers, 12=data+backpointers\n"
" 13=coord lookup\n"
" 0= exit\n";
int mode;
bool finish = 0;
do
{
getNumber(prompt,mode, 1, false);
} while (mode < 1 || mode > 9 );
switch (mode)
{
case 1:
DF->Detach();
FindIntegers(DFMgr, selected_ranges);
break;
case 2:
DF->Detach();
FindVectorByLength(DFMgr, selected_ranges);
break;
case 3:
DF->Detach();
FindVectorByObjectRawname(DFMgr, selected_ranges);
break;
case 4:
DF->Detach();
FindStrings(DFMgr, selected_ranges);
break;
case 5:
automatedLangtables(DF,selected_ranges);
break;
case 6:
DF->Detach();
FindVectorByBounds(DFMgr,selected_ranges);
break;
case 7:
DF->Detach();
FindPtrVectorsByObjectAddress(DFMgr,selected_ranges);
break;
case 8:
DF->Detach();
FindVectorByFirstObjectRawname(DFMgr, selected_ranges);
break;
case 9:
DF->Detach();
FindStrBufs(DFMgr, selected_ranges);
break;
default:
cout << "not implemented :(" << endl;
}
switch (mode)
{
case 0:
finish = 1;
break;
case 1:
DF->Detach();
FindIntegers(DFMgr, selected_ranges);
break;
case 2:
DF->Detach();
FindVectorByLength(DFMgr, selected_ranges);
break;
case 3:
DF->Detach();
FindVectorByObjectRawname(DFMgr, selected_ranges);
break;
case 4:
DF->Detach();
FindStrings(DFMgr, selected_ranges);
break;
case 5:
autoSearch(DF,selected_ranges);
break;
case 6:
DF->Detach();
FindVectorByBounds(DFMgr,selected_ranges);
break;
case 7:
DF->Detach();
FindPtrVectorsByObjectAddress(DFMgr,selected_ranges);
break;
case 8:
DF->Detach();
FindVectorByFirstObjectRawname(DFMgr, selected_ranges);
break;
case 9:
DF->Detach();
FindStrBufs(DFMgr, selected_ranges);
break;
case 10:
DF->Detach();
FindData(DFMgr, selected_ranges);
break;
case 11:
DF->Detach();
PtrTrace(DFMgr, selected_ranges);
break;
case 12:
DF->Detach();
DataPtrTrace(DFMgr, selected_ranges);
break;
case 13:
DF->Detach();
FindCoords(DFMgr, selected_ranges);
break;
default:
cout << "Unknown function, try again." << endl;
}
} while ( !finish );
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();

@ -1,22 +1,31 @@
// This will create 7 deep magama on the square the cursor is on. It does not
// enable magma buildings at this time.
// TO BE DEPRECATED SOON.
#include <iostream>
#include <vector>
#include <map>
#include <cstdlib>
using namespace std;
#include <DFHack.h>
#include <dfhack/DFTileTypes.h>
int main (void)
int main (int argc, char** argv)
{
bool quiet = false;
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-q")
{
quiet = true;
}
}
int32_t x,y,z;
DFHack::designations40d designations;
DFHack::tiletypes40d tiles;
DFHack::t_temperatures temp1,temp2;
uint32_t x_max,y_max,z_max;
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF;
DFHack::Maps * Maps;
@ -45,6 +54,8 @@ int main (void)
string flowmode="f+";
string setmode ="s.";
int amount = 7;
int width = 1;
int height = 1;
while(!end)
{
DF->Resume();
@ -68,7 +79,8 @@ int main (void)
<< "f- - make the spawned liquid static" << endl
<< "0-7 - set liquid amount" << endl
<< "Brush:" << endl
<< "point - single tile" << endl
<< "point - single tile [p]" << endl
<< "range - rectangle with cursor at top left [r]" << endl
<< "block - block with cursor in it" << endl
<< "Other:" << endl
<< "q - quit" << endl
@ -106,10 +118,22 @@ int main (void)
{
mode = "flowbits";
}
else if(command == "point")
else if(command == "point" || command == "p")
{
brush = "point";
}
else if(command == "range" || command == "r")
{
cout << " :set range width<" << width << "># ";
getline(cin, command);
width = command == "" ? width : atoi (command.c_str());
if(width < 1) width = 1;
cout << " :set range height<" << height << "># ";
getline(cin, command);
height = command == "" ? height : atoi (command.c_str());
if(height < 1) height = 1;
brush = "range";
}
else if(command == "block")
{
brush = "block";
@ -214,7 +238,6 @@ int main (void)
cout << "sizeof(tiletypes) = " << sizeof(tiles) << endl;
for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++)
{
cout<< xx << " " << yy <<": " << tiles[xx][yy] << endl;
tiles[xx][yy] = 335;// 45
DFHack::naked_designation & des = designations[xx][yy].bits;
@ -224,10 +247,8 @@ int main (void)
des.skyview = 0;
des.light = 0;
des.subterranean = 1;
temp1[xx][yy] = 10015;
temp2[xx][yy] = 10015;
}
Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2);
Maps->WriteDesignations((x/16),(y/16),z, &designations);
@ -257,46 +278,18 @@ int main (void)
else
{
// place the magma
Maps->ReadDesignations((x/16),(y/16),z, &designations);
Maps->ReadTemperatures((x/16),(y/16),z, &temp1, &temp2);
if(brush == "point")
{
if(mode != "flowbits")
{
// fix temperatures so we don't produce lethal heat traps
if(amount == 0 || designations[x%16][y%16].bits.liquid_type == DFHack::liquid_magma && mode == "water")
temp1[x%16][y%16] = temp2[x%16][y%16] = 10015;
DFHack::naked_designation & flow = designations[x%16][y%16].bits;
if(setmode == "s.")
{
flow.flow_size = amount;
}
else if(setmode == "s+")
{
if(flow.flow_size < amount)
flow.flow_size = amount;
}
else if(setmode == "s-")
{
if (flow.flow_size > amount)
flow.flow_size = amount;
}
}
if(mode == "magma")
designations[x%16][y%16].bits.liquid_type = DFHack::liquid_magma;
else if(mode == "water")
designations[x%16][y%16].bits.liquid_type = DFHack::liquid_water;
}
else
if(brush != "range")
{
for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++)
Maps->ReadDesignations((x/16),(y/16),z, &designations);
Maps->ReadTemperatures((x/16),(y/16),z, &temp1, &temp2);
if(brush == "point")
{
if(mode != "flowbits")
{
// fix temperatures so we don't produce lethal heat traps
if(amount == 0 || designations[xx][yy].bits.liquid_type == DFHack::liquid_magma && mode == "water")
temp1[xx%16][yy%16] = temp2[xx%16][yy%16] = 10015;
DFHack::naked_designation & flow= designations[xx][yy].bits;
if(amount == 0 || designations[x%16][y%16].bits.liquid_type == DFHack::liquid_magma && mode == "water")
temp1[x%16][y%16] = temp2[x%16][y%16] = 10015;
DFHack::naked_designation & flow = designations[x%16][y%16].bits;
if(setmode == "s.")
{
flow.flow_size = amount;
@ -313,36 +306,162 @@ int main (void)
}
}
if(mode == "magma")
designations[xx][yy].bits.liquid_type = DFHack::liquid_magma;
designations[x%16][y%16].bits.liquid_type = DFHack::liquid_magma;
else if(mode == "water")
designations[xx][yy].bits.liquid_type = DFHack::liquid_water;
designations[x%16][y%16].bits.liquid_type = DFHack::liquid_water;
}
else
{
for(uint32_t xx = 0; xx < 16; xx++) for(uint32_t yy = 0; yy < 16; yy++)
{
if(mode != "flowbits")
{
// fix temperatures so we don't produce lethal heat traps
if(amount == 0 || designations[xx][yy].bits.liquid_type == DFHack::liquid_magma && mode == "water")
temp1[xx%16][yy%16] = temp2[xx%16][yy%16] = 10015;
DFHack::naked_designation & flow= designations[xx][yy].bits;
if(setmode == "s.")
{
flow.flow_size = amount;
}
else if(setmode == "s+")
{
if(flow.flow_size < amount)
flow.flow_size = amount;
}
else if(setmode == "s-")
{
if (flow.flow_size > amount)
flow.flow_size = amount;
}
}
if(mode == "magma")
designations[xx][yy].bits.liquid_type = DFHack::liquid_magma;
else if(mode == "water")
designations[xx][yy].bits.liquid_type = DFHack::liquid_water;
}
}
Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2);
Maps->WriteDesignations(x/16,y/16,z, &designations);
// make the magma flow :)
DFHack::t_blockflags bflags;
Maps->ReadBlockFlags((x/16),(y/16),z,bflags);
// 0x00000001 = job-designated
// 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow
if(flowmode == "f+")
{
bflags.bits.liquid_1 = true;
bflags.bits.liquid_2 = true;
}
else if(flowmode == "f-")
{
bflags.bits.liquid_1 = false;
bflags.bits.liquid_2 = false;
}
else
{
cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl;
cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl;
}
Maps->WriteBlockFlags((x/16),(y/16),z,bflags);
}
Maps->WriteTemperatures((x/16),(y/16),z, &temp1, &temp2);
Maps->WriteDesignations(x/16,y/16,z, &designations);
}
// make the magma flow :)
DFHack::t_blockflags bflags;
Maps->ReadBlockFlags((x/16),(y/16),z,bflags);
// 0x00000001 = job-designated
// 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow
if(flowmode == "f+")
{
bflags.bits.liquid_1 = true;
bflags.bits.liquid_2 = true;
}
else if(flowmode == "f-")
{
bflags.bits.liquid_1 = false;
bflags.bits.liquid_2 = false;
}
else
{
cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl;
cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl;
else if (brush == "range")
{
// Crop the range into each block if necessary
int beginxblock = x/16;
int endxblock = (x+width)/16;
int beginyblock = y/16;
int endyblock = (y+height)/16;
for(uint32_t bx = beginxblock; bx < endxblock+1; bx++) for(uint32_t by = beginyblock; by < endyblock+1; by++)
{
if(Maps->isValidBlock(bx,by,z))
{
Maps->ReadDesignations(bx,by,z, &designations);
Maps->ReadTemperatures(bx,by,z, &temp1, &temp2);
// Take original range and crop it into current block
int nx = x;
int ny = y;
int nwidth = width;
int nheight = height;
if(x/16 < bx) //Start point is left of block
{
nx = bx*16;
nwidth -= nx - x;
}
if (nx/16 < (nx+nwidth-1)/16)// End point is right of block
{
nwidth = (bx*16)+16-nx;
}
if(y/16 < by) //Start point is above block
{
ny = by*16;
nheight -= ny - y;
}
if (ny/16 < (ny+nheight-1)/16) // End point is below block
{
nheight = (by*16)+16-ny;
}
cout << " Block:" << bx << "," << by << ":" << endl;
cout << " Start:" << nx << "," << ny << ":" << endl;
cout << " Area: " << nwidth << "," << nheight << ":" << endl;
for(uint32_t xx = nx; xx < nx+nwidth; xx++) for(uint32_t yy = ny; yy < ny+nheight; yy++)
{
if(mode != "flowbits")
{
// fix temperatures so we don't produce lethal heat traps
if(amount == 0 || designations[xx%16][yy%16].bits.liquid_type == DFHack::liquid_magma && mode == "water")
temp1[xx%16][yy%16] = temp2[xx%16][yy%16] = 10015;
DFHack::naked_designation & flow= designations[xx%16][yy%16].bits;
if(setmode == "s.")
{
flow.flow_size = amount;
}
else if(setmode == "s+")
{
if(flow.flow_size < amount)
flow.flow_size = amount;
}
else if(setmode == "s-")
{
if (flow.flow_size > amount)
flow.flow_size = amount;
}
}
if(mode == "magma")
designations[xx%16][yy%16].bits.liquid_type = DFHack::liquid_magma;
else if(mode == "water")
designations[xx%16][yy%16].bits.liquid_type = DFHack::liquid_water;
}
Maps->WriteTemperatures(bx,by,z, &temp1, &temp2);
Maps->WriteDesignations(bx,by,z, &designations);
// make the magma flow :)
DFHack::t_blockflags bflags;
Maps->ReadBlockFlags(bx,by,z,bflags);
// 0x00000001 = job-designated
// 0x0000000C = run flows? - both bit 3 and 4 required for making magma placed on a glacier flow
if(flowmode == "f+")
{
bflags.bits.liquid_1 = true;
bflags.bits.liquid_2 = true;
}
else if(flowmode == "f-")
{
bflags.bits.liquid_1 = false;
bflags.bits.liquid_2 = false;
}
else
{
cout << "flow bit 1 = " << bflags.bits.liquid_1 << endl;
cout << "flow bit 2 = " << bflags.bits.liquid_2 << endl;
}
Maps->WriteBlockFlags(bx,by,z,bflags);
}
}
}
}
Maps->WriteBlockFlags((x/16),(y/16),z,bflags);
cout << "OK" << endl;
Maps->Finish();
} while (0);
@ -350,8 +469,11 @@ int main (void)
}
DF->Detach();
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
if(!quiet)
{
cout << "Done. Press any key to continue" << endl;
cin.ignore();
}
#endif
return 0;
}

@ -8,8 +8,18 @@ using namespace std;
#include <DFHack.h>
int main (void)
int main (int argc, char** argv)
{
bool quiet = false;
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-q")
{
quiet = true;
}
}
DFHack::Position * Position = 0;
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context * DF;
@ -31,7 +41,7 @@ int main (void)
{
int32_t x,y,z;
int32_t width,height;
if(Position->getViewCoords(x,y,z))
cout << "view coords: " << x << "/" << y << "/" << z << endl;
if(Position->getCursorCoords(x,y,z))
@ -43,15 +53,18 @@ int main (void)
{
cerr << "cursor and window parameters are unsupported on your version of DF" << endl;
}
if(!DF->Detach())
{
cerr << "Can't detach from DF" << endl;
}
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
if(!quiet)
{
cout << "Done. Press any key to continue" << endl;
cin.ignore();
}
#endif
return 0;
}

@ -8,8 +8,8 @@
#include <ctime>
#include <cstdio>
#define DFHACK_WANT_MISCUTILS
#define DFHACK_WANT_TILETYPES
#define DFHACK_WANT_MISCUTILS 1
#define DFHACK_WANT_TILETYPES 1
#include <DFHack.h>
using namespace DFHack;
@ -17,7 +17,8 @@ int main (int numargs, const char ** args)
{
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF = DFMgr.getSingleContext();
BEGIN_PROBE:
try
{
DF->Attach();
@ -31,6 +32,7 @@ int main (int numargs, const char ** args)
return 1;
}
DFHack::Position *Pos = DF->getPosition();
DFHack::VersionInfo* mem = DF->getMemoryInfo();
DFHack::Maps *Maps = DF->getMaps();
@ -57,6 +59,11 @@ int main (int numargs, const char ** args)
Maps->Start();
vector<DFHack::t_feature> global_features;
std::map <DFHack::planecoord, std::vector<DFHack::t_feature *> > local_features;
Maps->ReadLocalFeatures(local_features);
Maps->ReadGlobalFeatures(global_features);
int32_t cursorX, cursorY, cursorZ;
Pos->getCursorCoords(cursorX,cursorY,cursorZ);
if(cursorX != -30000)
@ -82,7 +89,15 @@ int main (int numargs, const char ** args)
// tiletype
std::cout <<"tiletype: " << tiletype;
if(tileTypeTable[tiletype].name)
std::cout << " = " << tileTypeTable[tiletype].name;
std::cout << " = " << tileTypeTable[tiletype].name << std::endl;
printf("%-10s: %4d %s\n","Class",tileTypeTable[tiletype].c,TileClassString[ tileTypeTable[tiletype].c ] , 0);
printf("%-10s: %4d %s\n","Material",tileTypeTable[tiletype].c,TileMaterialString[ tileTypeTable[tiletype].m ] , 0);
printf("%-10s: %4d %s\n","Special",tileTypeTable[tiletype].c,TileSpecialString[ tileTypeTable[tiletype].s ] , 0);
printf("%-10s: %4d\n","Variant",tileTypeTable[tiletype].v , 0);
printf("%-10s: %s\n","Direction",tileTypeTable[tiletype].d.getStr() , 0);
std::cout << std::endl;
std::cout <<"temperature1: " << tmpb1[tileX][tileY] << " U" << std::endl;
std::cout <<"temperature2: " << tmpb2[tileX][tileY] << " U" << std::endl;
@ -109,24 +124,45 @@ int main (int numargs, const char ** args)
std::cout << "smooth?" << std::endl;
uint32_t designato = block.origin + designatus + (tileX * 16 + tileY) * sizeof(t_designation);
printf("designation offset: 0x%x\n", designato);
if(des.light)
std::cout << "Light ";
else
std::cout << " ";
if(des.skyview)
std::cout << "SkyView ";
else
std::cout << " ";
if(des.subterranean)
std::cout << "Underground ";
else
std::cout << " ";
#define PRINT_FLAG( X ) printf("%-16s= %c\n", #X , ( des.X ? 'Y' : ' ' ) )
PRINT_FLAG( hidden );
PRINT_FLAG( light );
PRINT_FLAG( skyview );
PRINT_FLAG( subterranean );
PRINT_FLAG( water_table );
//PRINT_FLAG( rained );
planecoord pc;
pc.dim.x=blockX; pc.dim.y=blockY;
PRINT_FLAG( feature_local );
if( des.feature_local )
{
printf("%-16s %4d (%2d) %s\n", "",
block.local_feature,
local_features[pc][block.local_feature]->type,
sa_feature[local_features[pc][block.local_feature]->type]
);
}
PRINT_FLAG( feature_global );
if( des.feature_global ){
printf("%-16s %4d (%2d) %s\n", "",
block.global_feature,
global_features[block.global_feature].type,
sa_feature[global_features[block.global_feature].type]
);
}
#undef PRINT_FLAG
std::cout << std::endl;
}
}
DF->Detach();
#ifndef LINUX_BUILD
std::cout << "Done. Press any key to continue" << std::endl;
cin.ignore();
std::cout << "Press any key to refresh..." << std::endl;
cin.ignore();
goto BEGIN_PROBE;
#endif
return 0;
}

@ -41,10 +41,9 @@ struct compare_pair_second
int main (int argc, const char* argv[])
{
bool showhidden = false;
bool showbaselayers = false;
for(int i = 0; i < argc; i++)
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-a")
@ -76,9 +75,9 @@ int main (int argc, const char* argv[])
materials.clear();
vector<DFHack::t_feature> global_features;
std::map <DFHack::planecoord, std::vector<DFHack::t_feature *> > local_features;
vector< vector <uint16_t> > layerassign;
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF;
try
@ -94,11 +93,10 @@ int main (int argc, const char* argv[])
#endif
return 1;
}
DFHack::Maps * Maps = DF->getMaps();
DFHack::Materials * Mats = DF->getMaterials();
// init the map
if(!Maps->Start())
{
@ -109,7 +107,7 @@ int main (int argc, const char* argv[])
return 1;
}
Maps->getSize(x_max,y_max,z_max);
if(!Maps->ReadGlobalFeatures(global_features))
{
cerr << "Can't get global features." << endl;
@ -137,7 +135,7 @@ int main (int argc, const char* argv[])
#endif
return 1;
}
// get region geology
if(!Maps->ReadGeology( layerassign ))
{
@ -147,7 +145,7 @@ int main (int argc, const char* argv[])
#endif
return 1;
}
int16_t tempvein [16][16];
vector <DFHack::t_vein> veins;
uint32_t maximum_regionoffset = 0;
@ -161,16 +159,16 @@ int main (int argc, const char* argv[])
{
if(!Maps->isValidBlock(x,y,z))
continue;
// read data
Maps->ReadBlock40d(x,y,z, &Block);
//Maps->ReadTileTypes(x,y,z, &tiletypes);
//Maps->ReadDesignations(x,y,z, &designations);
memset(tempvein, -1, sizeof(tempvein));
veins.clear();
Maps->ReadVeins(x,y,z,&veins);
if(showbaselayers)
{
//Maps->ReadRegionOffsets(x,y,z, &regionoffsets);
@ -194,7 +192,7 @@ int main (int argc, const char* argv[])
}
}
}
// for each vein
for(int i = 0; i < (int)veins.size();i++)
{
@ -214,7 +212,7 @@ int main (int argc, const char* argv[])
}
}
}
// global feature overrides
int16_t idx = Block.global_feature;
if( idx != -1 && uint16_t(idx) < global_features.size() && global_features[idx].type == DFHack::feature_Underworld)
@ -234,7 +232,7 @@ int main (int argc, const char* argv[])
}
}
}
idx = Block.local_feature;
if( idx != -1 )
{
@ -263,7 +261,7 @@ int main (int argc, const char* argv[])
}
}
}
// count the material types
for(uint32_t xi = 0 ; xi< 16 ; xi++)
{
@ -275,7 +273,7 @@ int main (int argc, const char* argv[])
continue;
if(tempvein[xi][yi] < 0)
continue;
if(materials.count(tempvein[xi][yi]))
{
materials[tempvein[xi][yi]] += 1;

@ -10,45 +10,44 @@ using namespace std;
#include <DFHack.h>
#include <dfhack/DFTileTypes.h>
#include <argstream.h>
//#include <argstream.h>
#define MAX_DIM 0x300
class Point
//TODO: turn into the official coord class for DFHack/DF
class Vertex
{
public:
Point(uint32_t x, uint32_t y, uint32_t z)
{
this->x = x;
this->y = y;
this->z = z;
}
Point()
Vertex(uint32_t _x, uint32_t _y, uint32_t _z):x(_x),y(_y),z(_z) {}
Vertex()
{
x = y = z = 0;
}
bool operator==(const Point &other) const
bool operator==(const Vertex &other) const
{
return (other.x == x && other.y == y && other.z == z);
}
bool operator<(const Point &other) const
// FIXME: <tomprince> peterix_: you could probably get away with not defining operator< if you defined a std::less specialization for Vertex.
bool operator<(const Vertex &other) const
{
// FIXME: could be changed to eliminate MAX_DIM and make std::map lookups faster?
return ( (z*MAX_DIM*MAX_DIM + y*MAX_DIM + x) < (other.z*MAX_DIM*MAX_DIM + other.y*MAX_DIM + other.x));
}
Point operator/(int number) const
Vertex operator/(int number) const
{
return Point(x/number, y/number, z);
return Vertex(x/number, y/number, z);
}
Point operator%(int number) const
Vertex operator%(int number) const
{
return Point(x%number, y%number, z);
return Vertex(x%number, y%number, z);
}
Point operator-(int number) const
Vertex operator-(int number) const
{
return Point(x,y,z-number);
return Vertex(x,y,z-number);
}
Point operator+(int number) const
Vertex operator+(int number) const
{
return Point(x,y,z+number);
return Vertex(x,y,z+number);
}
uint32_t x;
uint32_t y;
@ -58,7 +57,7 @@ class Point
class Block
{
public:
Block(DFHack::Maps *_m, Point _bcoord)
Block(DFHack::Maps *_m, Vertex _bcoord)
{
vector <DFHack::t_vein> veins;
m = _m;
@ -97,23 +96,23 @@ class Block
valid = true;
}
}
int16_t MaterialAt(Point p)
int16_t MaterialAt(Vertex p)
{
return materials[p.x][p.y];
}
void ClearMaterialAt(Point p)
void ClearMaterialAt(Vertex p)
{
materials[p.x][p.y] = -1;
}
int16_t TileTypeAt(Point p)
int16_t TileTypeAt(Vertex p)
{
return raw.tiletypes[p.x][p.y];
}
DFHack::t_designation DesignationAt(Point p)
DFHack::t_designation DesignationAt(Vertex p)
{
return raw.designation[p.x][p.y];
}
bool setDesignationAt(Point p, DFHack::t_designation des)
bool setDesignationAt(Vertex p, DFHack::t_designation des)
{
if(!valid) return false;
dirty = true;
@ -136,7 +135,7 @@ class Block
volatile bool dirty;
DFHack::Maps * m;
DFHack::mapblock40d raw;
Point bcoord;
Vertex bcoord;
int16_t materials[16][16];
int8_t bitmap[16][16];
};
@ -153,7 +152,7 @@ class MapCache
};
~MapCache()
{
map<Point, Block *>::iterator p;
map<Vertex, Block *>::iterator p;
for(p = blocks.begin(); p != blocks.end(); p++)
{
delete p->second;
@ -165,11 +164,11 @@ class MapCache
return valid;
}
Block * BlockAt (Point blockcoord)
Block * BlockAt (Vertex blockcoord)
{
if(!valid) return 0;
map <Point, Block*>::iterator iter = blocks.find(blockcoord);
map <Vertex, Block*>::iterator iter = blocks.find(blockcoord);
if(iter != blocks.end())
{
return (*iter).second;
@ -186,7 +185,7 @@ class MapCache
}
}
uint16_t tiletypeAt (Point tilecoord)
uint16_t tiletypeAt (Vertex tilecoord)
{
Block * b= BlockAt(tilecoord / 16);
if(b && b->valid)
@ -196,7 +195,7 @@ class MapCache
return 0;
}
int16_t materialAt (Point tilecoord)
int16_t materialAt (Vertex tilecoord)
{
Block * b= BlockAt(tilecoord / 16);
if(b && b->valid)
@ -205,7 +204,7 @@ class MapCache
}
return 0;
}
bool clearMaterialAt (Point tilecoord)
bool clearMaterialAt (Vertex tilecoord)
{
Block * b= BlockAt(tilecoord / 16);
if(b && b->valid)
@ -216,7 +215,7 @@ class MapCache
}
DFHack::t_designation designationAt (Point tilecoord)
DFHack::t_designation designationAt (Vertex tilecoord)
{
Block * b= BlockAt(tilecoord / 16);
if(b && b->valid)
@ -227,7 +226,7 @@ class MapCache
temp.whole = 0;
return temp;
}
bool setDesignationAt (Point tilecoord, DFHack::t_designation des)
bool setDesignationAt (Vertex tilecoord, DFHack::t_designation des)
{
Block * b= BlockAt(tilecoord / 16);
if(b && b->valid)
@ -237,7 +236,7 @@ class MapCache
}
return false;
}
bool testCoord (Point tilecoord)
bool testCoord (Vertex tilecoord)
{
Block * b= BlockAt(tilecoord / 16);
if(b && b->valid)
@ -249,7 +248,7 @@ class MapCache
bool WriteAll()
{
map<Point, Block *>::iterator p;
map<Vertex, Block *>::iterator p;
for(p = blocks.begin(); p != blocks.end(); p++)
{
p->second->WriteDesignations();
@ -265,17 +264,19 @@ class MapCache
uint32_t y_tmax;
uint32_t z_max;
DFHack::Maps * Maps;
map<Point, Block *> blocks;
map<Vertex, Block *> blocks;
};
int main (int argc, char* argv[])
{
// Command line options
bool updown = false;
/*
argstream as(argc,argv);
as >>option('x',"updown",updown,"Dig up and down stairs to reach other z-levels.")
>>help();
// sane check
if (!as.isOk())
@ -283,6 +284,9 @@ int main (int argc, char* argv[])
cout << as.errorLog();
return 1;
}
*/
if(argc > 1 && strcmp(argv[1],"-x") == 0)
updown = true;
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context * DF;
@ -299,12 +303,12 @@ int main (int argc, char* argv[])
#endif
return 1;
}
uint32_t x_max,y_max,z_max;
DFHack::Maps * Maps = DF->getMaps();
DFHack::Materials * Mats = DF->getMaterials();
DFHack::Position * Pos = DF->getPosition();
// init the map
if(!Maps->Start())
{
@ -315,12 +319,12 @@ int main (int argc, char* argv[])
#endif
return 1;
}
int32_t cx, cy, cz;
Maps->getSize(x_max,y_max,z_max);
uint32_t tx_max = x_max * 16;
uint32_t ty_max = y_max * 16;
Pos->getCursorCoords(cx,cy,cz);
while(cx == -30000)
{
@ -330,7 +334,7 @@ int main (int argc, char* argv[])
DF->Suspend();
Pos->getCursorCoords(cx,cy,cz);
}
Point xy ((uint32_t)cx,(uint32_t)cy,cz);
Vertex xy ((uint32_t)cx,(uint32_t)cy,cz);
if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1)
{
cerr << "I won't dig the borders. That would be cheating!" << endl;
@ -358,13 +362,13 @@ int main (int argc, char* argv[])
return 1;
}
printf("%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole);
stack <Point> flood;
stack <Vertex> flood;
flood.push(xy);
while( !flood.empty() )
{
Point current = flood.top();
Vertex current = flood.top();
flood.pop();
int16_t vmat2 = MCache->materialAt(current);
@ -402,30 +406,30 @@ int main (int argc, char* argv[])
MCache->clearMaterialAt(current);
if(current.x < tx_max - 2)
{
flood.push(Point(current.x + 1, current.y, current.z));
flood.push(Vertex(current.x + 1, current.y, current.z));
if(current.y < ty_max - 2)
{
flood.push(Point(current.x + 1, current.y + 1,current.z));
flood.push(Point(current.x, current.y + 1,current.z));
flood.push(Vertex(current.x + 1, current.y + 1,current.z));
flood.push(Vertex(current.x, current.y + 1,current.z));
}
if(current.y > 1)
{
flood.push(Point(current.x + 1, current.y - 1,current.z));
flood.push(Point(current.x, current.y - 1,current.z));
flood.push(Vertex(current.x + 1, current.y - 1,current.z));
flood.push(Vertex(current.x, current.y - 1,current.z));
}
}
if(current.x > 1)
{
flood.push(Point(current.x - 1, current.y,current.z));
flood.push(Vertex(current.x - 1, current.y,current.z));
if(current.y < ty_max - 2)
{
flood.push(Point(current.x - 1, current.y + 1,current.z));
flood.push(Point(current.x, current.y + 1,current.z));
flood.push(Vertex(current.x - 1, current.y + 1,current.z));
flood.push(Vertex(current.x, current.y + 1,current.z));
}
if(current.y > 1)
{
flood.push(Point(current.x - 1, current.y - 1,current.z));
flood.push(Point(current.x, current.y - 1,current.z));
flood.push(Vertex(current.x - 1, current.y - 1,current.z));
flood.push(Vertex(current.x, current.y - 1,current.z));
}
}
if(updown)

@ -536,6 +536,7 @@ main(int argc, char *argv[])
vector<t_vein> veinVector;
vector<t_frozenliquidvein> IceVeinVector;
vector<t_spattervein> splatter;
vector<t_grassvein> grass;
t_temperatures b_temp1;
t_temperatures b_temp2;
@ -549,7 +550,6 @@ main(int argc, char *argv[])
{
pDF = DF = DFMgr.getSingleContext();
DF->Attach();
Mats = DF->getMaterials();
Maps = DF->getMaps();
}
catch (exception& e)
@ -560,6 +560,15 @@ main(int argc, char *argv[])
#endif
finish(0);
}
bool hasmats = true;
try
{
Mats = DF->getMaterials();
}
catch (exception& e)
{
hasmats = false;
}
Process* p = DF->getProcess();
// init the map
@ -568,27 +577,32 @@ main(int argc, char *argv[])
error = "Can't find a map to look at.";
finish(0);
}
Maps->getSize(x_max_a,y_max_a,z_max_a);
x_max = x_max_a;
y_max = y_max_a;
z_max = z_max_a;
// get stone matgloss mapping
if(!Mats->ReadInorganicMaterials())
{
error = "Can't read stone types.";
pDF = 0;
finish(0);
}
/*
if(!Mats->ReadCreatureTypes())
bool hasInorgMats = false;
bool hasPlantMats = false;
bool hasCreatureMats = false;
if(hasmats)
{
error = "Can't read stone types.";
pDF = 0;
finish(0);
// get stone matgloss mapping
if(Mats->ReadInorganicMaterials())
{
hasInorgMats = true;
}
if(Mats->ReadCreatureTypes())
{
hasCreatureMats = true;
}
if(Mats->ReadOrganicMaterials())
{
hasPlantMats = true;
}
}
*/
/*
// get region geology
if(!DF.ReadGeology( layerassign ))
@ -620,7 +634,9 @@ main(int argc, char *argv[])
{
TEMP_NO,
TEMP_1,
TEMP_2
TEMP_2,
WATER_SALT,
WATER_STAGNANT
};
e_tempmode temperature = TEMP_NO;
@ -691,6 +707,12 @@ main(int argc, char *argv[])
case 'm':
temperature = TEMP_2;
break;
case 'c':
temperature = WATER_SALT;
break;
case 'v':
temperature = WATER_STAGNANT;
break;
case 27: // escape key
DF->Detach();
return 0;
@ -715,15 +737,29 @@ main(int argc, char *argv[])
IceVeinVector.clear();
effects.clear();
splatter.clear();
grass.clear();
dirtybit = 0;
// Supend, read/write data
DF->Suspend();
// restart cleared modules
Maps->Start();
Mats->Start();
Mats->ReadInorganicMaterials();
Mats->ReadCreatureTypes();
if(hasmats)
{
Mats->Start();
if(hasInorgMats)
{
Mats->ReadInorganicMaterials();
}
if(hasPlantMats)
{
Mats->ReadOrganicMaterials();
}
if(hasCreatureMats)
{
Mats->ReadCreatureTypes();
}
}
uint32_t effectnum;
/*
if(DF.InitReadEffects(effectnum))
@ -739,22 +775,21 @@ main(int argc, char *argv[])
for(int i = -1; i <= 1; i++) for(int j = -1; j <= 1; j++)
{
mapblock40d * Block = &blocks[i+1][j+1];
if(Maps->isValidBlock(cursorX+i,cursorY+j,cursorZ))
{
Maps->ReadBlock40d(cursorX+i,cursorY+j,cursorZ, Block);
// extra processing of the block in the middle
if(i == 0 && j == 0)
{
do_features(DF, Block, cursorX, cursorY, 50,10, Mats->inorganic);
if(hasInorgMats)
do_features(DF, Block, cursorX, cursorY, 50,10, Mats->inorganic);
// read veins
Maps->ReadVeins(cursorX+i,cursorY+j,cursorZ,&veinVector,&IceVeinVector,&splatter);
Maps->ReadVeins(cursorX+i,cursorY+j,cursorZ,&veinVector,&IceVeinVector,&splatter,&grass);
// get pointer to block
blockaddr = Maps->getBlockPtr(cursorX+i,cursorY+j,cursorZ);
blockaddr2 = Block->origin;
// dig all veins and trees
if(dig)
{
@ -849,11 +884,12 @@ main(int argc, char *argv[])
uint32_t mineralsize = veinVector.size();
uint32_t icesize = IceVeinVector.size();
uint32_t splattersize = splatter.size();
uint32_t totalVeinSize = mineralsize+ icesize + splattersize;
uint32_t grasssize = grass.size();
uint32_t totalVeinSize = mineralsize+ icesize + splattersize + grasssize;
if(vein == totalVeinSize) vein = totalVeinSize - 1;
if(vein < -1) vein = -1;
cprintf("X %d/%d, Y %d/%d, Z %d/%d. Vein %d of %d",cursorX+1,x_max,cursorY+1,y_max,cursorZ,z_max,vein+1,totalVeinSize);
if(!veinVector.empty() || !IceVeinVector.empty() || !splatter.empty())
if(!veinVector.empty() || !IceVeinVector.empty() || !splatter.empty() || !grass.empty())
{
if(vein != -1 && vein < totalVeinSize)
{
@ -883,8 +919,11 @@ main(int argc, char *argv[])
}
}
}
gotoxy(50,3);
cprintf("Mineral: %s",Mats->inorganic[veinVector[vein].type].id);
if(hasInorgMats)
{
gotoxy(50,3);
cprintf("Mineral: %s",Mats->inorganic[veinVector[vein].type].id);
}
}
else if (vein < mineralsize + icesize)
{
@ -906,7 +945,7 @@ main(int argc, char *argv[])
gotoxy(50,3);
cprintf("ICE");
}
else
else if(vein < mineralsize + icesize + splattersize)
{
realvein = vein - mineralsize - icesize;
t_spattervein &bloodmud = splatter[realvein];
@ -923,8 +962,31 @@ main(int argc, char *argv[])
}
}
}
if(hasCreatureMats)
{
gotoxy(50,3);
cprintf("Spatter: %s",PrintSplatterType(splatter[realvein].mat1,splatter[realvein].mat2,Mats->race).c_str());
}
}
else
{
realvein = vein - mineralsize - icesize - splattersize;
t_grassvein & grassy =grass[realvein];
for(uint32_t yyy = 0; yyy < 16; yyy++)
{
for(uint32_t xxx = 0; xxx < 16; xxx++)
{
uint8_t intensity = grassy.intensity[xxx][yyy];
if(intensity)
{
attron(A_STANDOUT);
putch(xxx+16,yyy+16,'X', COLOR_RED);
attroff(A_STANDOUT);
}
}
}
gotoxy(50,3);
cprintf("Spatter: %s",PrintSplatterType(splatter[realvein].mat1,splatter[realvein].mat2,Mats->race).c_str());
cprintf("Grass: 0x%x, %s",grassy.address_of, Mats->organic[grassy.material].id);
}
}
}
@ -940,6 +1002,30 @@ main(int argc, char *argv[])
}
}
}
else if(temperature == WATER_SALT)
{
for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
{
if(Block->designation[x][y].bits.water_salt)
{
putch(x + 16,y + 16,'@',COLOR_WHITE);
}
}
gotoxy (50,8);
cprintf ("Salt water");
}
else if(temperature == WATER_STAGNANT)
{
for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
{
if(Block->designation[x][y].bits.water_stagnant)
{
putch(x + 16,y + 16,'@',COLOR_WHITE);
}
}
gotoxy (50,8);
cprintf ("Stagnant water");
}
else
{
if(temperature == TEMP_1)

@ -43,8 +43,25 @@ void printWeather(DFHack::WeatherType current)
}
using namespace DFHack;
int main (int numargs, const char ** args)
int main (int argc, char** argv)
{
string command = "";
bool quiet = false;
bool cmdarg = false;
for(int i = 1; i < argc; i++)
{
string test = argv[i];
if(test == "-q")
{
quiet = true;
}
else
{
command = test;
cmdarg = true;
}
}
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF = DFMgr.getSingleContext();
@ -68,9 +85,8 @@ int main (int numargs, const char ** args)
{
WeatherType current = (WeatherType) W->ReadCurrentWeather();
DF->Resume();
string command = "";
printWeather(current);
getline(cin, command);
if (command == "") getline(cin, command); // only read from stdin if command hasn't been passed on the console
DF->Suspend();
if(command == "c")
{
@ -88,11 +104,17 @@ int main (int numargs, const char ** args)
{
end = true;
}
command = "";
if(cmdarg) end = true; // exit the loop when a cmd line arg has been passed.
}
#ifndef LINUX_BUILD
std::cout << "Done. Press any key to continue" << std::endl;
cin.ignore();
if (!quiet)
{
std::cout << "Done. Press any key to continue" << std::endl;
cin.ignore();
}
#endif
DF->Resume();
DF->Detach();
return 0;
}