code moved from khazad

develop
Petr Mrázek 2009-09-14 00:02:46 +00:00
parent 52f768f6c5
commit fac88478bd
48 changed files with 13564 additions and 0 deletions

@ -0,0 +1,30 @@
# main project file. use it from a build sub-folder, see COMPILE for details
PROJECT (dfhack)
cmake_minimum_required(VERSION 2.6)
# disable warning, autosearch
if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)
if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")
message(SEND_ERROR "In-source builds are not allowed.")
endif("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")
IF(NOT DEFINED CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
ENDIF(NOT DEFINED CMAKE_BUILD_TYPE)
SET(SO_MAJOR_VERSION "0")
SET(SO_MINOR_VERSION "0")
SET(SO_BUILD_VERSION "1")
SET(SO_VERSION "${SO_MAJOR_VERSION}.${SO_MINOR_VERSION}.${SO_BUILD_VERSION}")
SET( LIBRARY_OUTPUT_PATH ${dfhack_SOURCE_DIR}/output CACHE PATH "Output directory for the dfhack library" )
SET( EXECUTABLE_OUTPUT_PATH ${dfhack_SOURCE_DIR}/output CACHE PATH "Output directory for the dfhack tools" )
include_directories (${CMAKE_SOURCE_DIR}/library/)
add_subdirectory (library)
add_subdirectory (tools)

@ -0,0 +1,55 @@
Here's how you build dfhack!
----------------------------
First, there is one dependency:
cmake - it's the build system
building the library is simple. Enter the build folder, run th tools. Like this:
cd build
cmake .. -DCMAKE_BUILD_TYPE:string=Release
make
Changing folder to build and using 'cmake ..' is important!
This will build the library and its tools and place them in /output.
You can also use a cmake-friendly IDE like KDevelop 4 or the cmake GUI program.
Building on Windows:
--------------------
You need cmake. Get the win32 installer version from the official site: http://www.cmake.org/cmake/resources/software.html
It has the usual installer wizard thing.
* Using mingw:
You also need a compiler. I build dfhack using mingw. You can get it from the mingw site:
Get the automated installer, it will download newest version of mingw and set things up nicely.
You'll have to add C:\MinGW\ to your PATH variable.
- Building:
open up cmd and navigate to the dfhack\build folder, run cmake and the mingw version of make:
cd build
cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release
mingw32-make
* Using some other compiler:
I'm afraid you are on your own. dfhack wasn't tested with any other compiler.
Try using a different cmake generator that's intended for your tools.
Build targets
-------------
dfhack has a few build targets. If you're only after the library run 'make dfhack'.
'make' will build everything.
'make expbench' will build the expbench throughput testing program and the library.
Build types
-----------
cmake allows you to pick a build type by changing this variable: CMAKE_BUILD_TYPE
cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE
Without specifying a build type or 'None', cmake uses the CMAKE_CXX_FLAGS variable for building.
Valid build types include 'Release' and 'Debug'. There are others, but they aren't really that useful.
Have fun.

@ -0,0 +1,21 @@
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.

@ -0,0 +1,47 @@
Introduction
------------
DFHack is a Dwarf Fortress memory access library and a set of basic tools using this library.
The library is a work in progress, so things might change as more tools are written for it.
Getting DFHack
----------------
You can get the code or a release at DFHack's sourceforge site:
https://sourceforge.net/projects/dfhack/
* subversion access:
svn co https://dfhack.svn.sourceforge.net/svnroot/dfhack/trunk dfhack
Using the library
-----------------
The library should be compilable under Linux with GCC and under Windows with MinGW32
compiler. It is using the cmake build system. See COMPILE for details.
Main part of the API is in SimpleAPI.h
You might also have to include a few other files:
Types.h - defines many of the used data structures
TileTypes.h - functions for translating map tile type values to useful properties
(wall, flooer, etc.)
Memory offset definitions
-------------------------
The file with memory offset definitions used by dfhack can be found in the output folder.
TODO: write format explanation
Tools
-----
All the DFHack tools are terminal programs. This might seem strange to Windows users,
but they are meant mostly as examples for developers. Still, they can be useful and
are cross-platform just like the library itself.
* expbench - just exports the map 1000 times over. Meant to test how fast the
DFHack<->DF interface is. This should take 3-12 seconds.
* reveal - plain old reveal tool. Demonstrates writing map data back to DF.
* prospector - scans the map for minerals. by default it only scans only visible veins.
You can make it show hidden things with '-a' and base rock and soil layers
with '-b'. These can be combined ('-ab')
* cleanmap - cleans mud, vomit, snow and all kinds of bloody mess from the map. It will
clean your irrigated farms too, so consider yourself warned.

@ -0,0 +1,3 @@
[Project]
Manager=KDevCMakeManager
Name=dfhack

@ -0,0 +1,25 @@
# don't use this file directly. use the one in the root folder of the project
SET(PROJECT_SRCS
DFDataModel.cpp
DFMemInfo.cpp
DFProcess.cpp
DFProcessManager.cpp
DFHackAPI.cpp
DFTileTypes.cpp
md5/md5.cpp
md5/md5wrapper.cpp
tinyxml/tinystr.cpp
tinyxml/tinyxml.cpp
tinyxml/tinyxmlerror.cpp
tinyxml/tinyxmlparser.cpp
)
IF(UNIX)
add_definitions(-DLINUX_BUILD)
ELSE(UNIX)
SET(PROJECT_LIBS psapi)
ENDIF(UNIX)
ADD_LIBRARY(dfhack SHARED ${PROJECT_SRCS})
TARGET_LINK_LIBRARIES(dfhack ${PROJECT_LIBS})

@ -0,0 +1,63 @@
/*
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 DFCOMMON_H_INCLUDED
#define DFCOMMON_H_INCLUDED
///TODO: separate into extrenal and internal
#include <string>
#include <vector>
#include <map>
//#include <boost/bimap/bimap.hpp>
//using namespace boost::bimaps;
#include <fstream>
using namespace std;
#include <stdint.h>
#include <assert.h>
#include <string.h>
#ifdef LINUX_BUILD
#include <sys/types.h>
#include <sys/ptrace.h>
#include <dirent.h>
#else
#define WINVER 0x0501 // OpenThread(), PSAPI, Toolhelp32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winbase.h>
#include <winnt.h>
#include <psapi.h>
#endif
#include "DFTypes.h"
#include "DFDataModel.h"
#include "DFProcessManager.h"
#include "DFMemAccess.h"
#include "DFVector.h"
//#include "DfMap.h"
#endif // DFCOMMON_H_INCLUDED

@ -0,0 +1,105 @@
/*
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 "DFCommon.h"
DfVector DMWindows40d::readVector (uint32_t offset, uint32_t item_size)
{
/*
MSVC++ vector is four pointers long
ptr allocator
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
we also don't care about the allocator thing in front
*/
uint32_t start = MreadDWord(offset+4);
uint32_t end = MreadDWord(offset+8);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
};
const string DMWindows40d::readSTLString (uint32_t offset)
{
/*
MSVC++ string
ptr allocator
union
{
char[16] start;
char * start_ptr
}
Uint32 length
Uint32 capacity
*/
uint32_t start_offset = offset + 4;
uint32_t length = MreadDWord(offset + 20);
uint32_t capacity = MreadDWord(offset + 24);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
Mread(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = MreadDWord(start_offset);// dereference the start offset
Mread(start_offset, capacity, (uint8_t *)temp);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
};
DfVector DMLinux40d::readVector (uint32_t offset, uint32_t item_size)
{
/*
GNU libstdc++ vector is three pointers long
ptr start
ptr end
ptr alloc_end
we don't care about alloc_end because we don't try to add stuff
*/
uint32_t start = MreadDWord(offset);
uint32_t end = MreadDWord(offset+4);
uint32_t size = (end - start) /4;
return DfVector(start,size,item_size);
};
const string DMLinux40d::readSTLString (uint32_t offset)
{
// GNU std::string is a single pointer (as far as we are concerned)
offset = MreadDWord(offset);
return MreadCString(offset);
};

@ -0,0 +1,54 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef DATAMODEL_H_INCLUDED
#define DATAMODEL_H_INCLUDED
class DfVector;
// let's go pure virtual.
class DataModel
{
public:
// read a string
virtual const string readSTLString (uint32_t offset) = 0;
// read a vector from memory
virtual DfVector readVector (uint32_t offset, uint32_t item_size) = 0;
};
class DMWindows40d : public DataModel
{
virtual const string readSTLString (uint32_t offset);
// read a vector from memory
virtual DfVector readVector (uint32_t offset, uint32_t item_size);
};
class DMLinux40d : public DataModel
{
virtual const string readSTLString (uint32_t offset);
// read a vector from memory
virtual DfVector readVector (uint32_t offset, uint32_t item_size);
};
#endif // DATAMODEL_H_INCLUDED

@ -0,0 +1,596 @@
/*
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 "DFCommon.h"
#include "DFVector.h"
#include "DFHackAPI.h"
#include "DFMemInfo.h"
/* TODO: Test these
ReadVegetation
ReadConstruction
ReadBuilding
matgloss other than stone/soil
*/
// TODO: templating for vectors, simple copy constructor for stl vectors
// TODO: encapsulate access to multidimensional arrays.
DFHackAPI::DFHackAPI(const string path_to_xml)
{
xml = path_to_xml;
constructionsInited = false;
buildingsInited = false;
vegetationInited = false;
pm = NULL;
}
/*-----------------------------------*
* Init the mapblock pointer array *
*-----------------------------------*/
bool DFHackAPI::InitMap()
{
uint32_t map_loc, // location of the X array
temp_loc, // block location
temp_locx, // iterator for the X array
temp_locy, // iterator for the Y array
temp_locz; // iterator for the Z array
uint32_t map_offset = offset_descriptor->getAddress("map_data");
uint32_t x_count_offset = offset_descriptor->getAddress("x_count");
uint32_t y_count_offset = offset_descriptor->getAddress("y_count");
uint32_t z_count_offset = offset_descriptor->getAddress("z_count");
// get the offsets once here
tile_type_offset = offset_descriptor->getOffset("type");
designation_offset = offset_descriptor->getOffset("designation");
occupancy_offset = offset_descriptor->getOffset("occupancy");
// get the map pointer
map_loc = MreadDWord(map_offset);
if (!map_loc)
{
// bad stuffz happend
return false;
}
// get the size
x_block_count = MreadDWord(x_count_offset);
y_block_count = MreadDWord(y_count_offset);
z_block_count = MreadDWord(z_count_offset);
// alloc array for pinters to all blocks
block = new uint32_t[x_block_count*y_block_count*z_block_count];
//read the memory from the map blocks - x -> map slice
for(uint32_t x = 0; x < x_block_count; x++)
{
temp_locx = map_loc + ( 4 * x );
temp_locy = MreadDWord(temp_locx);
// y -> map column
for(uint32_t y = 0; y < y_block_count; y++)
{
temp_locz = MreadDWord(temp_locy);
temp_locy += 4;
// z -> map block (16x16)
for(uint32_t z = 0; z < z_block_count; z++)
{
temp_loc = MreadDWord(temp_locz);
temp_locz += 4;
block[x*y_block_count*z_block_count + y*z_block_count + z] = temp_loc;
}
}
}
return true;
}
bool DFHackAPI::isValidBlock(uint32_t x, uint32_t y, uint32_t z)
{
return block[x*y_block_count*z_block_count + y*z_block_count + z] != NULL;
}
// 256 * sizeof(uint16_t)
bool DFHackAPI::ReadTileTypes(uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer)
{
uint32_t addr = block[x*y_block_count*z_block_count + y*z_block_count + z];
if (addr!=NULL)
{
Mread(addr+tile_type_offset, 256 * sizeof(uint16_t), (uint8_t *)buffer);
return true;
}
return false;
}
// 256 * sizeof(uint32_t)
bool DFHackAPI::ReadDesignations(uint32_t x, uint32_t y, uint32_t z, uint32_t *buffer)
{
uint32_t addr = block[x*y_block_count*z_block_count + y*z_block_count + z];
if (addr!=NULL)
{
Mread(addr+designation_offset, 256 * sizeof(uint32_t), (uint8_t *)buffer);
return true;
}
return false;
}
// 256 * sizeof(uint32_t)
bool DFHackAPI::ReadOccupancy(uint32_t x, uint32_t y, uint32_t z, uint32_t *buffer)
{
uint32_t addr = block[x*y_block_count*z_block_count + y*z_block_count + z];
if (addr!=NULL)
{
Mread(addr+occupancy_offset, 256 * sizeof(uint32_t), (uint8_t *)buffer);
return true;
}
return false;
}
// 256 * sizeof(uint16_t)
bool DFHackAPI::WriteTileTypes(uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer)
{
uint32_t addr = block[x*y_block_count*z_block_count + y*z_block_count + z];
if (addr!=NULL)
{
Mwrite(addr+tile_type_offset, 256 * sizeof(uint16_t), (uint8_t *)buffer);
return true;
}
return false;
}
// 256 * sizeof(uint32_t)
bool DFHackAPI::WriteDesignations(uint32_t x, uint32_t y, uint32_t z, uint32_t *buffer)
{
uint32_t addr = block[x*y_block_count*z_block_count + y*z_block_count + z];
if (addr!=NULL)
{
Mwrite(addr+designation_offset, 256 * sizeof(uint32_t), (uint8_t *)buffer);
return true;
}
return false;
}
// 256 * sizeof(uint32_t)
bool DFHackAPI::WriteOccupancy(uint32_t x, uint32_t y, uint32_t z, uint32_t *buffer)
{
uint32_t addr = block[x*y_block_count*z_block_count + y*z_block_count + z];
if (addr!=NULL)
{
Mwrite(addr+occupancy_offset, 256 * sizeof(uint32_t), (uint8_t *)buffer);
return true;
}
return false;
}
//16 of them? IDK... there's probably just 7. Reading more doesn't cause errors as it's an array nested inside a block
// 16 * sizeof(uint8_t)
bool DFHackAPI::ReadRegionOffsets(uint32_t x, uint32_t y, uint32_t z, uint8_t *buffer)
{
uint32_t biome_stuffs = offset_descriptor->getOffset("biome_stuffs");
uint32_t addr = block[x*y_block_count*z_block_count + y*z_block_count + z];
if (addr!=NULL)
{
Mread(addr+biome_stuffs, 16 * sizeof(uint8_t), buffer);
return true;
}
return false;
}
// veins of a block, expects empty vein vector
bool DFHackAPI::ReadVeins(uint32_t x, uint32_t y, uint32_t z, vector <t_vein> & veins)
{
uint32_t addr = block[x*y_block_count*z_block_count + y*z_block_count + z];
int veinvector = offset_descriptor->getOffset("v_vein");
int veinsize = offset_descriptor->getHexValue("v_vein_size");
veins.clear();
if(addr!=NULL && veinvector && veinsize)
{
assert(sizeof(t_vein) == veinsize);
// veins are stored as a vector of pointers to veins
/*pointer is 4 bytes! we work with a 32bit program here, no matter what architecture we compile khazad for*/
DfVector p_veins = dm->readVector(addr + veinvector, 4);
// read all veins
for (uint32_t i = 0; i< p_veins.getSize();i++)
{
t_vein v;
uint32_t temp;
// read the vein pointer from the vector
p_veins.read((uint32_t)i,(uint8_t *)&temp);
// read the vein data (dereference pointer)
Mread(temp, veinsize, (uint8_t *)&v);
// store it in the vector
veins.push_back(v);
}
return true;
}
return false;
}
// getter for map size
void DFHackAPI::getSize(uint32_t& x, uint32_t& y, uint32_t& z)
{
x = x_block_count;
y = y_block_count;
z = z_block_count;
}
bool DFHackAPI::ReadStoneMatgloss(vector<t_matgloss> & stones)
{
int matgloss_address = offset_descriptor->getAddress("matgloss");
int matgloss_offset = offset_descriptor->getHexValue("matgloss_skip");
int matgloss_colors = offset_descriptor->getOffset("matgloss_stone_color");
DfVector p_matgloss = dm->readVector(matgloss_address + matgloss_offset, 4);
stones.clear();
for (uint32_t i = 0; i< p_matgloss.getSize();i++)
{
uint32_t temp;
// read the matgloss pointer from the vector into temp
p_matgloss.read((uint32_t)i,(uint8_t *)&temp);
// read the string pointed at by
t_matgloss mat;
mat.id = dm->readSTLString(temp); // reads a C string given an address
mat.fore = MreadWord(temp + matgloss_colors);
mat.back = MreadWord(temp + matgloss_colors + 2);
mat.bright = MreadWord(temp + matgloss_colors + 4);
stones.push_back(mat);
}
return true;
}
bool DFHackAPI::ReadMetalMatgloss(vector<t_matgloss> & metals)
{
int matgloss_address = offset_descriptor->getAddress("matgloss");
int matgloss_offset = offset_descriptor->getHexValue("matgloss_skip");
int matgloss_colors = offset_descriptor->getOffset("matgloss_metal_color");
DfVector p_matgloss = dm->readVector(matgloss_address + matgloss_offset*2, 4);
metals.clear();
for (uint32_t i = 0; i< p_matgloss.getSize();i++)
{
uint32_t temp;
// read the matgloss pointer from the vector into temp
p_matgloss.read((uint32_t)i,(uint8_t *)&temp);
// read the string pointed at by
t_matgloss mat;
mat.id = dm->readSTLString(temp); // reads a C string given an address
mat.fore = MreadWord(temp + matgloss_colors);
mat.back = MreadWord(temp + matgloss_colors + 2);
mat.bright = MreadWord(temp + matgloss_colors + 4);
metals.push_back(mat);
}
return true;
}
bool DFHackAPI::ReadWoodMatgloss(vector<t_matgloss> & woods)
{
int matgloss_address = offset_descriptor->getAddress("matgloss");
// TODO: find flag for autumnal coloring?
DfVector p_matgloss = dm->readVector(matgloss_address, 4);
woods.clear();
t_matgloss mat;
// TODO: use brown?
mat.fore = 7;
mat.back = 0;
mat.bright = 0;
for (uint32_t i = 0; i< p_matgloss.getSize();i++)
{
uint32_t temp;
// read the matgloss pointer from the vector into temp
p_matgloss.read((uint32_t)i,(uint8_t *)&temp);
// read the string pointed at by
mat.id = dm->readSTLString(temp); // reads a C string given an address
woods.push_back(mat);
}
return true;
}
bool DFHackAPI::ReadPlantMatgloss(vector<t_matgloss> & plants)
{
int matgloss_address = offset_descriptor->getAddress("matgloss");
int matgloss_offset = offset_descriptor->getHexValue("matgloss_skip");
DfVector p_matgloss = dm->readVector(matgloss_address + matgloss_offset*3, 4);
plants.clear();
// TODO: use green?
t_matgloss mat;
mat.fore = 7;
mat.back = 0;
mat.bright = 0;
for (uint32_t i = 0; i< p_matgloss.getSize();i++)
{
uint32_t temp;
// read the matgloss pointer from the vector into temp
p_matgloss.read((uint32_t)i,(uint8_t *)&temp);
// read the string pointed at by
mat.id = dm->readSTLString(temp); // reads a C string given an address
plants.push_back(mat);
}
return true;
}
//vector<uint16_t> v_geology[eBiomeCount];
bool DFHackAPI::ReadGeology( vector < vector <uint16_t> >& assign )
{
// get needed addresses and offsets
int region_x_offset = offset_descriptor->getAddress("region_x");
int region_y_offset = offset_descriptor->getAddress("region_y");
int region_z_offset = offset_descriptor->getAddress("region_z");
int world_offset = offset_descriptor->getAddress("world");
int world_regions_offset = offset_descriptor->getOffset("w_regions_arr");
int region_size = offset_descriptor->getHexValue("region_size");
int region_geo_index_offset = offset_descriptor->getOffset("region_geo_index_off");
int world_geoblocks_offset = offset_descriptor->getOffset("w_geoblocks");
int world_size_x = offset_descriptor->getOffset("world_size_x");
int world_size_y = offset_descriptor->getOffset("world_size_y");
int geolayer_geoblock_offset = offset_descriptor->getOffset("geolayer_geoblock_offset");
uint32_t regionX, regionY, regionZ;
uint16_t worldSizeX, worldSizeY;
// check if we have 'em all
if(
!(
region_x_offset && region_y_offset && region_z_offset && world_size_x && world_size_y
&& world_offset && world_regions_offset && world_geoblocks_offset && region_size
&& region_geo_index_offset && geolayer_geoblock_offset
)
)
{
// fail if we don't have them
return false;
}
// read position of the region inside DF world
MreadDWord(region_x_offset, regionX);
MreadDWord(region_y_offset, regionY);
MreadDWord(region_z_offset, regionZ);
// get world size
MreadWord(world_offset + world_size_x, worldSizeX);
MreadWord(world_offset + world_size_y, worldSizeY);
// get pointer to first part of 2d array of regions
uint32_t regions = MreadDWord(world_offset + world_regions_offset);
// read the geoblock vector
DfVector geoblocks = dm->readVector(world_offset + world_geoblocks_offset,4);
// iterate over 8 surrounding regions + local region
for(int i = eNorthWest; i< eBiomeCount; i++)
{
// check bounds, fix them if needed
int bioRX = regionX / 16 + (i%3) - 1;
if( bioRX < 0) bioRX = 0;
if( bioRX >= worldSizeX) bioRX = worldSizeX - 1;
int bioRY = regionY / 16 + (i/3) - 1;
if( bioRY < 0) bioRY = 0;
if( bioRY >= worldSizeY) bioRY = worldSizeY - 1;
// get pointer to column of regions
uint32_t geoX;
MreadDWord(regions + bioRX*4, geoX);
// get index into geoblock vector
uint16_t geoindex;
MreadWord(geoX + bioRY*region_size + region_geo_index_offset, geoindex);
// get the geoblock from the geoblock vector using the geoindex
uint32_t geoblock_off;
geoblocks.read(geoindex,(uint8_t *) &geoblock_off);
// get the vector with pointer to layers
DfVector geolayers = dm->readVector(geoblock_off + geolayer_geoblock_offset , 4); // let's hope
// make sure we don't load crap
assert(geolayers.getSize() > 0 && geolayers.getSize() <= 16);
// finally, read the layer matgloss
for(uint32_t j = 0;j< geolayers.getSize();j++)
{
int geol_offset;
// read pointer to a layer
geolayers.read(j, (uint8_t *) & geol_offset);
// read word at pointer + 2, store in our geology vectors
v_geology[i].push_back(MreadWord(geol_offset + 2));
}
}
assign.clear();
// TODO: clean this up
for(int i = 0; i< eBiomeCount;i++)
{
assign.push_back(v_geology[i]);
}
return true;
}
// returns number of buildings, expects v_buildingtypes that will later map t_building.type to its name
uint32_t DFHackAPI::InitReadBuildings(vector <string> &v_buildingtypes)
{
buildingsInited = true;
int buildings = offset_descriptor->getAddress("buildings");
assert(buildings);
p_bld = new DfVector( dm->readVector(buildings,4));
offset_descriptor->copyBuildings(v_buildingtypes);
return p_bld->getSize();
}
// read one building
bool DFHackAPI::ReadBuilding(const uint32_t &index, t_building & building)
{
assert(buildingsInited);
uint32_t temp;
t_building_df40d bld_40d;
// read pointer from vector at position
p_bld->read(index,(uint8_t *)&temp);
//read building from memory
Mread(temp, sizeof(t_building_df40d), (uint8_t *)&bld_40d);
// transform
int32_t type = -1;
offset_descriptor->resolveClassId(temp, type);
building.vtable = bld_40d.vtable;
building.x1 = bld_40d.x1;
building.x2 = bld_40d.x2;
building.y1 = bld_40d.y1;
building.y2 = bld_40d.y2;
building.z = bld_40d.z;
building.material = bld_40d.material;
building.type = type;
}
void DFHackAPI::FinishReadBuildings()
{
buildingsInited = false;
}
//TODO: maybe do construction reading differently - this could go slow with many of them.
// returns number of constructions, prepares a vector, returns total number of constructions
uint32_t DFHackAPI::InitReadConstructions()
{
constructionsInited = true;
int constructions = offset_descriptor->getAddress("constructions");
assert(constructions);
p_cons = new DfVector(dm->readVector(constructions,4));
return p_cons->getSize();
}
bool DFHackAPI::ReadConstruction(const uint32_t &index, t_construction & construction)
{
assert(constructionsInited);
t_construction_df40d c_40d;
uint32_t temp;
// read pointer from vector at position
p_cons->read((uint32_t)index,(uint8_t *)&temp);
//read construction from memory
Mread(temp, sizeof(t_construction_df40d), (uint8_t *)&c_40d);
// transform
construction.x = c_40d.x;
construction.y = c_40d.y;
construction.z = c_40d.z;
construction.material = c_40d.material;
}
void DFHackAPI::FinishReadConstructions()
{
constructionsInited = false;
}
uint32_t DFHackAPI::InitReadVegetation()
{
vegetationInited = true;
int vegetation = offset_descriptor->getAddress("vegetation");
treeoffset = offset_descriptor->getOffset("tree_desc_offset");
assert(vegetation && treeoffset);
p_veg = new DfVector(dm->readVector(vegetation,4));
return p_veg->getSize();
}
bool DFHackAPI::ReadVegetation(const uint32_t &index, t_tree_desc & shrubbery)
{
assert(vegetationInited);
uint32_t temp;
// read pointer from vector at position
p_veg->read(index,(uint8_t *)&temp);
//read construction from memory
Mread(temp + treeoffset, sizeof(t_tree_desc), (uint8_t *) &shrubbery);
// FIXME: this is completely wrong. type isn't just tree/shrub but also different kinds of trees. stuff that grows around ponds has its own type ID
if(shrubbery.material.type == 3) shrubbery.material.type = 2;
}
void DFHackAPI::FinishReadVegetation()
{
vegetationInited = false;
}
bool DFHackAPI::Attach()
{
// detach all processes, destroy manager
if(pm != NULL)
delete pm;
// find a process (ProcessManager can find multiple when used properly)
pm = new ProcessManager(xml); // FIXME: handle bad XML better
if(!pm->findProcessess())
return false; // FIXME: throw exceptions to distinguish errors? provide error code?
p = (*pm)[0]; // we just use the first found process
if(!p->attach())
return false; // couldn't attach to process, no go
offset_descriptor = p->getDescriptor();
dm = p->getDataModel();
// process is attached, everything went just fine... hopefully
return true;
}
// TODO: clean inited stuff here
bool DFHackAPI::Detach()
{
p->detach();
if(pm != NULL)
delete pm;
pm = NULL;
p = NULL;
offset_descriptor = NULL;
dm = NULL;
return true;
}

@ -0,0 +1,160 @@
/*
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 SIMPLEAPI_H_INCLUDED
#define SIMPLEAPI_H_INCLUDED
class memory_info;
class DfVector;
class ProcessManager;
class Process;
class DataModel;
//FIXME: better control over state, creation and destruction
//TODO: give this the pimpl treatment?
class DFHackAPI
{
private:
// internals
uint32_t * block;
uint32_t x_block_count, y_block_count, z_block_count;
uint32_t regionX, regionY, regionZ;
uint32_t worldSizeX, worldSizeY;
uint32_t tile_type_offset;
uint32_t designation_offset;
uint32_t occupancy_offset;
ProcessManager* pm;
Process* p;
DataModel* dm;
memory_info* offset_descriptor;
vector<uint16_t> v_geology[eBiomeCount];
string xml;
bool constructionsInited;
bool buildingsInited;
bool vegetationInited;
uint32_t treeoffset;
DfVector *p_cons;
DfVector *p_bld;
DfVector *p_veg;
public:
DFHackAPI(const string path_to_xml);
bool Attach();
bool Detach();
bool isAttached();
/**
* Matgloss. next four methods look very similar. I could use two and move the processing one level up...
* I'll keep it like this, even with the code duplication as it will hopefully get more features and separate data types later.
* Yay for nebulous plans for a rock survey tool that tracks how much of which metal could be smelted from available resorces
*/
bool ReadStoneMatgloss(vector<t_matgloss> & output);
bool ReadWoodMatgloss (vector<t_matgloss> & output);
bool ReadMetalMatgloss(vector<t_matgloss> & output);
bool ReadPlantMatgloss(vector<t_matgloss> & output);
// FIXME: add creatures for all the creature products
// read region surroundings, get their vectors of geolayers so we can do translation (or just hand the translation table to the client)
// returns an array of 9 vectors of indices into stone matgloss
/**
Method for reading the geological surrounding of the currently loaded region.
assign is a reference to an array of nine vectors of unsigned words that are to be filled with the data
array is indexed by the BiomeOffset enum
I omitted resolving the layer matgloss in this API, because it would
introduce overhead by calling some method for each tile. You have to do it
yourself. First get the stuff from ReadGeology and then for each block get
the RegionOffsets. For each tile get the real region from RegionOffsets and
cross-reference it with the geology stuff (region -- array of vectors, depth --
vector). I'm thinking about turning that Geology stuff into a
two-dimensional array with static size.
this is the algorithm for applying matgloss:
void DfMap::applyGeoMatgloss(Block * b)
{
// load layer matgloss
for(int x_b = 0; x_b < BLOCK_SIZE; x_b++)
{
for(int y_b = 0; y_b < BLOCK_SIZE; y_b++)
{
int geolayer = b->designation[x_b][y_b].bits.geolayer_index;
int biome = b->designation[x_b][y_b].bits.biome;
b->material[x_b][y_b].type = Mat_Stone;
b->material[x_b][y_b].index = v_geology[b->RegionOffsets[biome]][geolayer];
}
}
}
*/
bool ReadGeology( vector < vector <uint16_t> >& assign );
/*
* BLOCK DATA
*/
/// allocate and read pointers to map blocks
bool InitMap();
/// destroy the mapblock cache
bool DestroyMap();
/// get size of the map in tiles
void getSize(uint32_t& x, uint32_t& y, uint32_t& z);
/**
* Return false/0 on failure, buffer allocated by client app, 256 items long
*/
bool isValidBlock(uint32_t blockx, uint32_t blocky, uint32_t blockz);
bool ReadTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t)
bool WriteTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t)
bool ReadDesignations(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint32_t *buffer); // 256 * sizeof(uint32_t)
bool WriteDesignations (uint32_t blockx, uint32_t blocky, uint32_t blockz, uint32_t *buffer);
bool ReadOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint32_t *buffer); // 256 * sizeof(uint32_t)
bool WriteOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint32_t *buffer); // 256 * sizeof(uint32_t)
/// read region offsets of a block
bool ReadRegionOffsets(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint8_t *buffer); // 16 * sizeof(uint8_t)
/// read aggregated veins of a block
bool ReadVeins(uint32_t blockx, uint32_t blocky, uint32_t blockz, vector <t_vein> & veins);
/**
* Buildings, constructions, plants, all pretty straighforward. InitReadBuildings returns all the building types as a mapping between a numeric values and strings
*/
uint32_t InitReadConstructions();
bool ReadConstruction(const uint32_t &index, t_construction & construction);
void FinishReadConstructions();
uint32_t InitReadBuildings(vector <string> &v_buildingtypes);
bool ReadBuilding(const uint32_t &index, t_building & building);
void FinishReadBuildings();
uint32_t InitReadVegetation();
bool ReadVegetation(const uint32_t &index, t_tree_desc & shrubbery);
void FinishReadVegetation();
};
#endif // SIMPLEAPI_H_INCLUDED

@ -0,0 +1,34 @@
/*
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 PROCESSUTIL_H_INCLUDED
#define PROCESSUTIL_H_INCLUDED
#ifdef LINUX_BUILD
#include "LinuxMemAccess.h"
#else
#include "WindowsMemAccess.h"
#endif
#endif // PROCESSUTIL_H_INCLUDED

@ -0,0 +1,382 @@
/*
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 "DFCommon.h"
#include "DFMemInfo.h"
#include <stdlib.h>
#include <iostream>
memory_info::memory_info()
{
base = 0;
classindex = 0;
}
void memory_info::setVersion(const char * v)
{
version = v;
}
void memory_info::setVersion(string v)
{
version = v;
}
string memory_info::getVersion()
{
return version;
}
void memory_info::setOS(const char *os)
{
string oss = os;
if(oss == "windows")
OS = OS_WINDOWS;
else if(oss == "linux")
OS = OS_LINUX;
else
OS = OS_BAD;
}
void memory_info::setOS(string os)
{
if(os == "windows")
OS = OS_WINDOWS;
else if(os == "linux")
OS = OS_LINUX;
else
OS = OS_BAD;
}
void memory_info::setOS(OSType os)
{
if(os >= OS_WINDOWS && os < OS_BAD)
{
OS = os;
return;
}
OS = OS_BAD;
}
memory_info::OSType memory_info::getOS()
{
return OS;
}
// copy constructor
memory_info::memory_info(const memory_info &old)
{
version = old.version;
OS = old.OS;
addresses = old.addresses;
offsets = old.offsets;
hexvals = old.hexvals;
strings = old.strings;
base = old.base;
classes = old.classes;
classsubtypes = old.classsubtypes;
classindex = old.classindex;
}
uint32_t memory_info::getBase ()
{
return base;
}
void memory_info::setBase (string s)
{
base = strtol(s.c_str(), NULL, 16);
}
void memory_info::setBase (uint32_t b)
{
base = b;
}
void memory_info::setOffset (string key, string value)
{
uint32_t offset = strtol(value.c_str(), NULL, 16);
offsets[key] = offset;
}
void memory_info::setAddress (string key, string value)
{
uint32_t address = strtol(value.c_str(), NULL, 16);
addresses[key] = address;
}
void memory_info::setHexValue (string key, string value)
{
uint32_t hexval = strtol(value.c_str(), NULL, 16);
hexvals[key] = hexval;
}
void memory_info::setString (string key, string value)
{
strings[key] = value;
}
// FIXME: next three methods should use some kind of custom container so it doesn't have to search so much.
void memory_info::setClass (const char * name, const char * vtable)
{
for (uint32_t i=0; i<classes.size(); i++)
{
if(classes[i].classname == name)
{
classes[i].vtable = strtol(vtable, NULL, 16);
return;
}
}
t_class cls;
cls.assign = classindex;
cls.classname = name;
cls.is_multiclass = false;
cls.type_offset = 0;
classindex++;
cls.vtable = strtol(vtable, NULL, 16);
classes.push_back(cls);
//cout << "class " << name << ", assign " << cls.assign << ", vtable " << cls.vtable << endl;
}
// find old entry by name, rewrite, return its multi index. otherwise make a new one, append an empty vector of t_type to classtypes, return its index.
uint32_t memory_info::setMultiClass (const char * name, const char * vtable, const char * typeoffset)
{
for (uint32_t i=0; i<classes.size(); i++)
{
if(classes[i].classname == name)
{
// vtable and typeoffset can be left out from the xml definition when there's already a named multiclass
if(vtable != NULL)
classes[i].vtable = strtol(vtable, NULL, 16);
if(typeoffset != NULL)
classes[i].type_offset = strtol(typeoffset, NULL, 16);
return classes[i].multi_index;
}
}
//FIXME: add checking for vtable and typeoffset here. they HAVE to be valid. maybe change the return value into a bool and pass in multi index by reference?
t_class cls;
cls.assign = classindex;
cls.classname = name;
cls.is_multiclass = true;
cls.type_offset = strtol(typeoffset, NULL, 16);
cls.vtable = strtol(vtable, NULL, 16);
cls.multi_index = classsubtypes.size();
classes.push_back(cls);
classindex++;
vector<t_type> thistypes;
classsubtypes.push_back(thistypes);
//cout << "multiclass " << name << ", assign " << cls.assign << ", vtable " << cls.vtable << endl;
return classsubtypes.size() - 1;
}
void memory_info::setMultiClassChild (uint32_t multi_index, const char * name, const char * type)
{
vector <t_type>& vec = classsubtypes[multi_index];
for (uint32_t i=0; i<vec.size(); i++)
{
if(vec[i].classname == name)
{
vec[i].type = strtol(type, NULL, 16);
return;
}
}
// new multiclass child
t_type mcc;
mcc.assign = classindex;
mcc.classname = name;
mcc.type = strtol(type, NULL, 16);
vec.push_back(mcc);
classindex++;
//cout << " classtype " << name << ", assign " << mcc.assign << ", vtable " << mcc.type << endl;
}
bool memory_info::resolveClassId(uint32_t address, int32_t & classid)
{
uint32_t vtable = MreadDWord(address);
// FIXME: stupid search. we need a better container
for(uint32_t i = 0;i< classes.size();i++)
{
if(classes[i].vtable == vtable) // got class
{
// if it is a multiclass, try resolving it
if(classes[i].is_multiclass)
{
vector <t_type>& vec = classsubtypes[classes[i].multi_index];
uint32_t type = MreadWord(address + classes[i].type_offset);
//printf ("class %d:%s offset 0x%x\n", i , classes[i].classname.c_str(), classes[i].type_offset);
// return typed building if successful
for (uint32_t k = 0; k < vec.size();k++)
{
if(vec[k].type == type)
{
//cout << " multi " << address + classes[i].type_offset << " " << vec[k].classname << endl;
classid = vec[k].assign;
return true;
}
}
}
// otherwise return the class we found
classid = classes[i].assign;
return true;
}
}
// we failed to find anything that would match
return false;
}
// Flatten vtables into a index<->name mapping
void memory_info::copyBuildings(vector<string> & v_buildingtypes)
{
for(uint32_t i = 0;i< classes.size();i++)
{
v_buildingtypes.push_back(classes[i].classname);
if(!classes[i].is_multiclass)
{
continue;
}
vector <t_type>& vec = classsubtypes[classes[i].multi_index];
for (uint32_t k = 0; k < vec.size();k++)
{
v_buildingtypes.push_back(vec[k].classname);
}
}
}
// change base of all addresses/vtable entries
void memory_info::RebaseAddresses(int32_t new_base)
{
map<string, uint32_t>::iterator iter;
int32_t rebase = - (int32_t)base + new_base;
for(iter = addresses.begin(); iter != addresses.end(); iter++)
{
addresses[iter->first] = iter->second + rebase;
}
}
// change base of all addresses/vtable entries
void memory_info::RebaseAll(int32_t new_base)
{
map<string, uint32_t>::iterator iter;
int32_t rebase = - (int32_t)base + new_base;
for(iter = addresses.begin(); iter != addresses.end(); iter++)
{
addresses[iter->first] = iter->second + rebase;
}
RebaseVTable(rebase);
}
// change all vtable entries by offset
void memory_info::RebaseVTable(int32_t offset)
{
vector<t_class>::iterator iter;
for(iter = classes.begin(); iter != classes.end(); iter++)
{
iter->vtable += offset;
}
}
// Get named address
uint32_t memory_info::getAddress (string key)
{
if(addresses.count(key))
{
return addresses[key];
}
return 0;
}
// Get named offset
uint32_t memory_info::getOffset (string key)
{
if(offsets.count(key))
{
return offsets[key];
}
return 0;
}
// Get named string
std::string memory_info::getString (string key)
{
if(strings.count(key))
{
return strings[key];
}
else return string("");
}
// Get named numerical value
uint32_t memory_info::getHexValue (string key)
{
if(hexvals.count(key))
{
return hexvals[key];
}
return 0;
}
// Reset everything
void memory_info::flush()
{
base = 0;
addresses.clear();
offsets.clear();
strings.clear();
hexvals.clear();
classes.clear();
classsubtypes.clear();
classindex = 0;
version = "";
OS = OS_BAD;
}

@ -0,0 +1,113 @@
/*
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 MEMINFO_H_INCLUDED
#define MEMINFO_H_INCLUDED
class memory_info
{
public:
enum OSType
{
OS_WINDOWS,
OS_LINUX,
OS_BAD
};
struct t_class
{
string classname;
uint32_t vtable;
bool is_multiclass;
uint32_t multi_index;
uint32_t assign;// index to typeclass array if multiclass. return value if not.
uint32_t type_offset; // offset of type data for multiclass
};
struct t_type
{
string classname;
uint32_t assign;
uint32_t type;
};
memory_info();
memory_info(const memory_info&);
void RebaseAddresses(int32_t new_base);
void RebaseAll(int32_t new_base);
uint32_t getBase ();
void setBase (string);
void setBase (uint32_t);
uint32_t getOffset (string);
uint32_t getAddress (string);
uint32_t getHexValue (string);
string getString (string);
void setVersion(const char *);
void setVersion(string);
string getVersion();
void setOS(const char *);
void setOS(string);
void setOS(OSType);
OSType getOS();
void setOffset (string, int32_t);
void setAddress (string, uint32_t);
void setHexValue (string, uint32_t);
void setOffset (string, const char *);
void setAddress (string, const char *);
void setHexValue (string, const char *);
void setString (string, const char *);
void setOffset (string, string);
void setAddress (string, string);
void setHexValue (string, string);
void setString (string, string);
void RebaseVTable(int32_t offset);
void setClass (const char * name, const char * vtable);
uint32_t setMultiClass (const char * name, const char * vtable, const char * typeoffset);
void setMultiClassChild (uint32_t multi_index, const char * name, const char * type);
// ALERT: uses memory reading directly
bool resolveClassId(uint32_t address, int32_t & classid);
void copyBuildings(vector<string> & v_buildingtypes);
void flush();
private:
map <string, uint32_t> addresses;
map <string, uint32_t> offsets;
map <string, uint32_t> hexvals;
map <string, string> strings;
vector<t_class> classes;
vector<vector<t_type> > classsubtypes;
int32_t base;
uint32_t classindex;
string version;
OSType OS;
};
#endif // MEMINFO_H_INCLUDED

@ -0,0 +1,160 @@
/*
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 "DFCommon.h"
#ifdef LINUX_BUILD
#include <sys/wait.h>
#endif
Process::Process(DataModel * dm, memory_info* mi, ProcessHandle ph, uint32_t pid)
{
my_datamodel = dm;
my_descriptor = mi;
my_handle = ph;
my_pid = pid;
attached = false;
}
Process::~Process()
{
if(attached)
{
detach();
}
// destroy data model. this is assigned by processmanager
delete my_datamodel;
freeResources();
}
DataModel *Process::getDataModel()
{
return my_datamodel;
}
memory_info * Process::getDescriptor()
{
return my_descriptor;
}
void Process::setMemFile(const string & memf)
{
assert(!attached);
memFile = memf;
}
#ifdef LINUX_BUILD
/*
* LINUX PART
*/
bool Process::attach()
{
// TODO: check for errors!
if(g_pProcess != NULL)
{
return false;
}
ptrace(PTRACE_ATTACH , my_handle, NULL, NULL);
wait(NULL); // wait for DF to be stopped.
attached = true;
// HACK: Set the global process variables
g_pProcess = this;
g_ProcessHandle = my_handle;
g_ProcessMemFile = fopen(memFile.c_str(),"rb");
return true; // we are attached
}
bool Process::detach()
{
// TODO: check for errors.
ptrace(PTRACE_DETACH, my_handle, NULL, NULL);
attached = false;
g_pProcess = NULL;
g_ProcessHandle = 0;
fclose(g_ProcessMemFile);// close /proc/PID/mem
g_ProcessMemFile = NULL;
return true;
}
void Process::freeResources()
{
// nil
};
#else
/*
* WINDOWS PART
*/
//FIXME: should support stopping and resuming the process
bool Process::attach()
{
if(DebugActiveProcess(my_pid))
{
attached = true;
g_pProcess = this;
g_ProcessHandle = my_handle;
return true;
}
return false;
}
bool Process::detach()
{
if(!attached)
{
return false;
}
if(DebugActiveProcessStop(my_pid))
{
attached = false;
g_pProcess = NULL;
g_ProcessHandle = 0;
return true;
}
return false;
}
void Process::freeResources()
{
// opened by process manager
CloseHandle(my_handle);
};
#endif

@ -0,0 +1,526 @@
/*
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 "DFCommon.h"
#include "DFDataModel.h"
#include "DFMemInfo.h"
#include "tinyxml/tinyxml.h"
#include <iostream>
/// HACK: global variables (only one process can be attached at the same time.)
Process * g_pProcess; ///< current process. non-NULL when picked
ProcessHandle g_ProcessHandle; ///< cache of handle to current process. used for speed reasons
FILE * g_ProcessMemFile; ///< opened /proc/PID/mem, valid when attached
#ifdef LINUX_BUILD
/*
* LINUX version of the process finder.
*/
#include "md5/md5wrapper.h"
Process* ProcessManager::addProcess(const string & exe,ProcessHandle PH, const string & memFile)
{
md5wrapper md5;
// get hash of the running DF process
string hash = md5.getHashFromFile(exe);
vector<memory_info>::iterator it;
// iterate over the list of memory locations
for ( it=meminfo.begin() ; it < meminfo.end(); it++ )
{
if(hash == (*it).getString("md5")) // are the md5 hashes the same?
{
memory_info * m = &*it;
Process * ret;
//cout <<"Found process " << PH << ". It's DF version " << m->getVersion() << "." << endl;
// df can run under wine on Linux
if(memory_info::OS_WINDOWS == (*it).getOS())
{
ret= new Process(new DMWindows40d(),m,PH, PH);
}
else if (memory_info::OS_LINUX == (*it).getOS())
{
ret= new Process(new DMLinux40d(),m,PH, PH);
}
else
{
// some error happened, continue with next process
continue;
}
// tell Process about the /proc/PID/mem file
ret->setMemFile(memFile);
processes.push_back(ret);
return ret;
}
}
return NULL;
}
bool ProcessManager::findProcessess()
{
DIR *dir_p;
struct dirent *dir_entry_p;
string dir_name;
string exe_link;
string cwd_link;
string cmdline_path;
string cmdline;
// ALERT: buffer overrun potential
char target_name[1024];
int target_result;
int errorcount;
int result;
errorcount=0;
result=0;
// Open /proc/ directory
dir_p = opendir("/proc/");
// Reading /proc/ entries
while(NULL != (dir_entry_p = readdir(dir_p)))
{
// Only PID folders (numbers)
if (strspn(dir_entry_p->d_name, "0123456789") != strlen(dir_entry_p->d_name))
{
continue;
}
// string manipulation - get /proc/PID/exe link and /proc/PID/mem names
dir_name = "/proc/";
dir_name += dir_entry_p->d_name;
dir_name += "/";
exe_link = dir_name + "exe";
string mem_name = dir_name + "mem";
// resolve /proc/PID/exe link
target_result = readlink(exe_link.c_str(), target_name, sizeof(target_name)-1);
if (target_result == -1)
{
// bad result from link resolution, continue with another processed
continue;
}
// make sure we have a null terminated string...
target_name[target_result] = 0;
// is this the regular linux DF?
if (strstr(target_name, "dwarfort.exe") != NULL)
{
exe_link = target_name;
// get PID
result = atoi(dir_entry_p->d_name);
// create linux process, add it to the vector
addProcess(exe_link,result,mem_name);
// continue with next process
continue;
}
// FIXME: this fails when the wine process isn't started from the 'current working directory'. strip path data from cmdline
// DF in wine?
if(strstr(target_name, "wine-preloader")!= NULL)
{
// get working directory
cwd_link = dir_name + "cwd";
target_result = readlink(cwd_link.c_str(), target_name, sizeof(target_name)-1);
target_name[target_result] = 0;
// got path to executable, do the same for its name
cmdline_path = dir_name + "cmdline";
ifstream ifs ( cmdline_path.c_str() , ifstream::in );
getline(ifs,cmdline);
if (cmdline.find("dwarfort.exe") != string::npos || cmdline.find("Dwarf Fortress.exe") != string::npos)
{
// put executable name and path together
exe_link = target_name;
exe_link += "/";
exe_link += cmdline;
// get PID
result = atoi(dir_entry_p->d_name);
// create wine process, add it to the vector
addProcess(exe_link,result,mem_name);
}
}
}
closedir(dir_p);
// return value depends on if we found some DF processes
if(processes.size())
{
return true;
}
return false;
}
#else
// some magic - will come in handy when we start doing debugger stuff on Windows
bool EnableDebugPriv()
{
bool bRET = FALSE;
TOKEN_PRIVILEGES tp;
HANDLE hToken;
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid))
{
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
if (hToken != INVALID_HANDLE_VALUE)
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.PrivilegeCount = 1;
if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, 0, 0))
{
bRET = TRUE;
}
CloseHandle(hToken);
}
}
}
return bRET;
}
// WINDOWS version of the process finder
bool ProcessManager::findProcessess()
{
// Get the list of process identifiers.
//TODO: make this dynamic. (call first to get the array size and second to really get process handles)
DWORD ProcArray[512], memoryNeeded, numProccesses;
HMODULE hmod = NULL;
DWORD junk;
HANDLE hProcess;
bool found = false;
IMAGE_NT_HEADERS32 pe_header;
IMAGE_SECTION_HEADER sections[16];
EnableDebugPriv();
if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) )
{
return false;
}
// Calculate how many process identifiers were returned.
numProccesses = memoryNeeded / sizeof(DWORD);
// iterate through processes
for ( int i = 0; i < numProccesses; i++ )
{
found = false;
// open process
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, ProcArray[i] );
if (NULL == hProcess)
continue;
// we've got some process, look at its first module
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk))
{
// TODO: check module filename to verify that it's DF!
// got base ;)
uint32_t base = (uint32_t)hmod;
// read from this process
g_ProcessHandle = hProcess;
uint32_t pe_offset = MreadDWord(base+0x3C);
Mread(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
Mread(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections );
// see if there's a version entry that matches this process
vector<memory_info>::iterator it;
for ( it=meminfo.begin() ; it < meminfo.end(); it++ )
{
// filter by OS
if(memory_info::OS_WINDOWS == (*it).getOS())
{
uint32_t pe_timestamp = (*it).getHexValue("pe_timestamp");
if (pe_timestamp == pe_header.FileHeader.TimeDateStamp)
{
printf("Match found! Using version %s.\n", (*it).getVersion().c_str());
// give the process a data model and memory layout fixed for the base of first module
memory_info *m = new memory_info(*it);
m->RebaseAll(base);
// keep track of created memory_info objects so we can destroy them later
destroy_meminfo.push_back(m);
// process is responsible for destroying its data model
Process *ret= new Process(new DMWindows40d(),m,hProcess, ProcArray[i]);
processes.push_back(ret);
found = true;
break; // break the iterator loop
}
}
}
// close handle of processes that aren't DF
if(!found)
{
CloseHandle(hProcess);
}
}
}
if(processes.size())
return true;
return false;
}
#endif
void ProcessManager::ParseVTable(TiXmlElement* vtable, memory_info& mem)
{
TiXmlElement* pClassEntry;
TiXmlElement* pClassSubEntry;
const char * rebase = vtable->Attribute("rebase");
if(rebase)
{
int32_t rebase_offset = strtol(rebase, NULL, 16);
mem.RebaseVTable(rebase_offset);
}
pClassEntry = vtable->FirstChildElement();
for(;pClassEntry;pClassEntry=pClassEntry->NextSiblingElement())
{
string type = pClassEntry->Value();
const char *cstr_name = pClassEntry->Attribute("name");
const char *cstr_vtable = pClassEntry->Attribute("vtable");
if(type== "class")
{
mem.setClass(cstr_name, cstr_vtable);
}
else if (type == "multiclass")
{
const char *cstr_typeoffset = pClassEntry->Attribute("typeoffset");
int mclass = mem.setMultiClass(cstr_name, cstr_vtable, cstr_typeoffset);
pClassSubEntry = pClassEntry->FirstChildElement();
for(;pClassSubEntry;pClassSubEntry=pClassSubEntry->NextSiblingElement())
{
type = pClassSubEntry->Value();
if(type== "class")
{
cstr_name = pClassSubEntry->Attribute("name");
const char *cstr_value = pClassSubEntry->Attribute("type");
mem.setMultiClassChild(mclass,cstr_name,cstr_value);
}
}
}
}
}
void ProcessManager::ParseEntry (TiXmlElement* entry, memory_info& mem, map <string ,TiXmlElement *>& knownEntries)
{
TiXmlElement* pMemEntry;
const char *cstr_version = entry->Attribute("version");
const char *cstr_os = entry->Attribute("os");
const char *cstr_base = entry->Attribute("base");
const char *cstr_rebase = entry->Attribute("rebase");
if(cstr_base)
{
string base = cstr_base;
ParseEntry(knownEntries[base], mem, knownEntries);
}
// mandatory attributes missing?
if(!(cstr_version && cstr_os))
{
cerr << "Bad entry in memory.xml detected, version or os attribute is missing.";
// skip if we don't have valid attributes
return;
}
string os = cstr_os;
mem.setVersion(cstr_version);
mem.setOS(cstr_os);
// offset inherited addresses by 'rebase'.
int32_t rebase = 0;
if(cstr_rebase)
{
rebase = mem.getBase() + strtol(cstr_rebase, NULL, 16);
mem.RebaseAddresses(rebase);
}
//set base to default, we're overwriting this because the previous rebase could cause havoc on Vista/7
if(os == "windows")
{
// set default image base. this is fixed for base relocation later
mem.setBase(0x400000);
}
else if(os == "linux")
{
// this is wrong... I'm not going to do base image relocation on linux though.
// users are free to use a sane kernel that doesn't do this kind of **** by default
mem.setBase(0x0);
}
else
{
cerr << "unknown operating system " << os << endl;
return;
}
// process additional entries
//cout << "Entry " << cstr_version << " " << cstr_os << endl;
pMemEntry = entry->FirstChildElement()->ToElement();
for(;pMemEntry;pMemEntry=pMemEntry->NextSiblingElement())
{
// only elements get processed
const char *cstr_type = pMemEntry->Value();
const char *cstr_name = pMemEntry->Attribute("name");
const char *cstr_value = pMemEntry->GetText();
// check for missing parts
string type, name, value;
type = cstr_type;
if(type == "VTable")
{
ParseVTable(pMemEntry, mem);
continue;
}
if( !(cstr_name && cstr_value))
{
cerr << "underspecified MemInfo entry" << endl;
continue;
}
name = cstr_name;
value = cstr_value;
if (type == "HexValue")
{
mem.setHexValue(name, value);
}
else if (type == "Address")
{
mem.setAddress(name, value);
}
else if (type == "Offset")
{
mem.setOffset(name, value);
}
else if (type == "String")
{
mem.setString(name, value);
}
else
{
cerr << "Unknown MemInfo type: " << type << endl;
}
} // for
} // method
// load the XML file with offsets
bool ProcessManager::loadDescriptors(string path_to_xml)
{
TiXmlDocument doc( path_to_xml.c_str() );
bool loadOkay = doc.LoadFile();
TiXmlHandle hDoc(&doc);
TiXmlElement* pElem;
TiXmlHandle hRoot(0);
memory_info mem;
if ( loadOkay )
{
// block: name
{
pElem=hDoc.FirstChildElement().Element();
// should always have a valid root but handle gracefully if it does
if (!pElem)
{
cerr << "no pElem found" << endl;
return false;
}
string m_name=pElem->Value();
if(m_name != "DFExtractor")
{
cerr << "DFExtractor != " << m_name << endl;
return false;
}
//cout << "got DFExtractor XML!" << endl;
// save this for later
hRoot=TiXmlHandle(pElem);
}
// transform elements
{
// trash existing list
meminfo.clear();
TiXmlElement* pMemInfo=hRoot.FirstChild( "MemoryDescriptors" ).FirstChild( "Entry" ).Element();
map <string ,TiXmlElement *> map_pNamedEntries;
vector <TiXmlElement *> v_pEntries;
for( ; pMemInfo; pMemInfo=pMemInfo->NextSiblingElement("Entry"))
{
v_pEntries.push_back(pMemInfo);
const char *id;
if(id= pMemInfo->Attribute("id"))
{
string str_id = id;
map_pNamedEntries[str_id] = pMemInfo;
}
}
for(uint32_t i = 0; i< v_pEntries.size();i++)
{
memory_info mem;
//FIXME: add a set of entries processed in a step of this cycle, use it to check for infinite loops
/* recursive */ParseEntry( v_pEntries[i] , mem , map_pNamedEntries);
meminfo.push_back(mem);
}
// process found things here
}
return true;
}
else
{
// load failed
cerr << "Can't load memory offsets from memory.xml" << endl;
return false;
}
}
uint32_t ProcessManager::size()
{
return processes.size();
};
Process * ProcessManager::operator[](uint32_t index)
{
assert(index < processes.size());
return processes[index];
};
ProcessManager::ProcessManager( string path_to_xml )
{
currentProcess = NULL;
currentProcessHandle = 0;
loadDescriptors( path_to_xml );
}
ProcessManager::~ProcessManager()
{
// delete all processes
for(uint32_t i = 0;i < processes.size();i++)
{
delete processes[i];
}
//delete all generated memory_info stuff
for(uint32_t i = 0;i < destroy_meminfo.size();i++)
{
delete destroy_meminfo[i];
}
}

@ -0,0 +1,97 @@
/*
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 PROCESSMANAGER_H_INCLUDED
#define PROCESSMANAGER_H_INCLUDED
#ifdef LINUX_BUILD
typedef pid_t ProcessHandle;
#else
typedef HANDLE ProcessHandle;
#endif
class memory_info;
class DataModel;
class TiXmlElement;
class Process;
/*
* Currently attached process and its handle
*/
extern Process * g_pProcess; ///< current process. non-NULL when picked
extern ProcessHandle g_ProcessHandle; ///< cache of handle to current process. used for speed reasons
extern FILE * g_ProcessMemFile; ///< opened /proc/PID/mem, valid when attached
class Process
{
friend class ProcessManager;
protected:
Process(DataModel * dm, memory_info* mi, ProcessHandle ph, uint32_t pid);
~Process();
DataModel* my_datamodel;
memory_info * my_descriptor;
ProcessHandle my_handle;
uint32_t my_pid;
string memFile;
bool attached;
void freeResources();
void setMemFile(const string & memf);
public:
// Set up stuff so we can read memory
bool attach();
bool detach();
// is the process still there?
memory_info *getDescriptor();
DataModel *getDataModel();
};
/*
* Process manager
*/
class ProcessManager
{
public:
ProcessManager( string path_to_xml);
~ProcessManager();
bool findProcessess();
uint32_t size();
Process * operator[](uint32_t index);
private:
// memory info entries loaded from a file
std::vector<memory_info> meminfo;
// vector to keep track of dynamically created memory_info entries
std::vector<memory_info *> destroy_meminfo;
Process * currentProcess;
ProcessHandle currentProcessHandle;
std::vector<Process *> processes;
bool loadDescriptors( string path_to_xml);
void ParseVTable(TiXmlElement* vtable, memory_info& mem);
void ParseEntry (TiXmlElement* entry, memory_info& mem, map <string ,TiXmlElement *>& knownEntries);
#ifdef LINUX_BUILD
Process* addProcess(const string & exe,ProcessHandle PH,const string & memFile);
#endif
};
#endif // PROCESSMANAGER_H_INCLUDED

File diff suppressed because it is too large Load Diff

@ -0,0 +1,37 @@
/*
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 TILETYPES_H_INCLUDED
#define TILETYPES_H_INCLUDED
/// TODO: turn into XML
bool isWallTerrain(int in);
bool isFloorTerrain(int in);
bool isRampTerrain(int in);
bool isStairTerrain(int in);
bool isOpenTerrain(int in);
int picktexture(int in);
#endif // TILETYPES_H_INCLUDED

@ -0,0 +1,250 @@
/*
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 TYPES_H_INCLUDED
#define TYPES_H_INCLUDED
struct t_matgloss
{
string id;
uint8_t fore; // Annoyingly the offset for this differs between types
uint8_t back;
uint8_t bright;
};
struct t_vein
{
uint32_t vtable;
int16_t type;
int16_t assignment[16];
int16_t unknown;
uint32_t flags;
};
struct t_matglossPair
{
int16_t type;
int16_t index;
};
// raw
struct t_construction_df40d
{
int16_t x;
int16_t y;
int16_t z;
int16_t unk1;
int16_t unk2;
t_matglossPair material; // 4B
// int16_t mat_type;
// int16_t mat_idx;
};
// cooked
struct t_construction
{
uint16_t x;
uint16_t y;
uint16_t z;
t_matglossPair material;
// int16_t mat_type;
// int16_t mat_idx;
};
/*
dword vtable;
int minx;
int miny;
int centerx;
int maxx;
int maxy;
int centery;
int z;
dword height_not_used;
word mattype;
word matgloss;
word type; // NOTE: the actual field is in a different place
*/
//raw
struct t_building_df40d
{
uint32_t vtable;
uint32_t x1;
uint32_t y1;
uint32_t centerx;
uint32_t x2;
uint32_t y2;
uint32_t centery;
uint32_t z;
uint32_t height;
t_matglossPair material;
// not complete
};
//cooked
struct t_building
{
uint32_t vtable;
uint32_t x1;
uint32_t y1;
uint32_t x2;
uint32_t y2;
uint32_t z;
t_matglossPair material;
uint32_t type;
// FIXME: not complete, we need building presence bitmaps for stuff like farm plots and stockpiles, orientation (N,E,S,W) and state (open/closed)
};
struct t_tree_desc
{
t_matglossPair material;
uint16_t x;
uint16_t y;
uint16_t z;
};
// FIXME: in order in which the raw vectors appear in df memory, move to XML
enum RawType
{
Mat_Wood,
Mat_Stone,
Mat_Plant,
Mat_Metal,
NUM_MATGLOSS_TYPES
};
enum BiomeOffset
{
eNorthWest,
eNorth,
eNorthEast,
eWest,
eHere,
eEast,
eSouthWest,
eSouth,
eSouthEast,
eBiomeCount
};
// TODO: research this further? consult DF hacker wizards?
union t_designation
{
uint32_t whole;
struct {
unsigned int flow_size : 3; // how much liquid is here?
unsigned int pile : 1; // stockpile?
/*
* All the different dig designations... needs more info, probably an enum
*/
unsigned int dig : 3;
unsigned int detail : 1;///<- wtf
unsigned int detail_event : 1;///<- more wtf
unsigned int hidden :1;
/*
* This one is rather involved, but necessary to retrieve the base layer matgloss index
* see http://www.bay12games.com/forum/index.php?topic=608.msg253284#msg253284 for details
*/
unsigned int geolayer_index :4;
unsigned int light : 1;
unsigned int subterranean : 1; // never seen the light of day?
unsigned int skyview : 1; // sky is visible now, it rains in here when it rains
/*
* Probably similar to the geolayer_index. Only with a different set of offsets and different data.
* we don't use this yet
*/
unsigned int biome : 4;
/*
0 = water
1 = magma
*/
unsigned int liquid_type : 1;
unsigned int water_table : 1; // srsly. wtf?
unsigned int rained : 1; // does this mean actual rain (as in the blue blocks) or a wet tile?
unsigned int traffic : 2; // needs enum
unsigned int flow_forbid : 1; // idk wtf bbq
unsigned int liquid_static : 1;
unsigned int moss : 1;// I LOVE MOSS
unsigned int feature_present : 1; // another wtf... is this required for magma pipes to work?
unsigned int liquid_character : 2; // those ripples on streams?
} bits;
};
// occupancy flags (rat,dwarf,horse,built wall,not build wall,etc)
union t_occupancy
{
uint32_t whole;
struct {
unsigned int building : 3;// building type... should be an enum?
// 7 = door
unsigned int unit : 1;
unsigned int unit_grounded : 1;
unsigned int item : 1;
// splatter. everyone loves splatter.
unsigned int mud : 1;
unsigned int vomit :1;
unsigned int debris1 :1;
unsigned int debris2 :1;
unsigned int debris3 :1;
unsigned int debris4 :1;
unsigned int blood_g : 1;
unsigned int blood_g2 : 1;
unsigned int blood_b : 1;
unsigned int blood_b2 : 1;
unsigned int blood_y : 1;
unsigned int blood_y2 : 1;
unsigned int blood_m : 1;
unsigned int blood_m2 : 1;
unsigned int blood_c : 1;
unsigned int blood_c2 : 1;
unsigned int blood_w : 1;
unsigned int blood_w2 : 1;
unsigned int blood_o : 1;
unsigned int blood_o2 : 1;
unsigned int slime : 1;
unsigned int slime2 : 1;
unsigned int blood : 1;
unsigned int blood2 : 1;
unsigned int debris5 : 1;
unsigned int snow : 1;
} bits;
struct {
unsigned int building : 3;// building type... should be an enum?
// 7 = door
unsigned int unit : 1;
unsigned int unit_grounded : 1;
unsigned int item : 1;
// splatter. everyone loves splatter.
unsigned int splatter : 26;
} unibits;
};
#endif // TYPES_H_INCLUDED

@ -0,0 +1,67 @@
/*
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 DFVECTOR_H_INCLUDED
#define DFVECTOR_H_INCLUDED
class DfVector
{
private:
// starting offset
uint32_t start;
// vector size
uint32_t size;
// vector item size
uint32_t item_size;
public:
DfVector(uint32_t _start, uint32_t _size, uint32_t _item_size):
start(_start),size(_size),item_size(_item_size) {};
DfVector(const DfVector & vec)
{
start = vec.start;
size = vec.size;
item_size = vec.item_size;
};
DfVector(){};
// get offset of the specified index
inline uint32_t operator[](uint32_t index)
{
assert(index < size);
return start + index*item_size;
};
// get vector size
inline uint32_t getSize()
{
return size;
};
// read item_size bytes from the right offset
inline void read (uint32_t index, uint8_t *target)
{
assert(index < size);
Mread (start + index*item_size, item_size, target);
};
};
#endif // DFVECTOR_H_INCLUDED

@ -0,0 +1,173 @@
/*
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.
*/
/**
* DO NOT USE THIS FILE DIRECTLY! USE MemAccess.h INSTEAD!
*/
#include <stdint.h>
inline
uint8_t MreadByte (const uint32_t &offset)
{
uint8_t val;
fseek(g_ProcessMemFile, offset,SEEK_SET);
fread ( &val, sizeof(uint8_t), 1, g_ProcessMemFile );
return val;
}
inline
void MreadByte (const uint32_t &offset, uint8_t &val )
{
fseek(g_ProcessMemFile, offset,SEEK_SET);
fread ( &val, sizeof(uint8_t), 1, g_ProcessMemFile );
}
inline
uint16_t MreadWord (const uint32_t &offset)
{
uint16_t val;
fseek(g_ProcessMemFile, offset,SEEK_SET);
fread ( &val, sizeof(uint16_t), 1, g_ProcessMemFile );
return val;
}
inline
void MreadWord (const uint32_t &offset, uint16_t &val)
{
fseek(g_ProcessMemFile, offset,SEEK_SET);
fread ( &val, sizeof(uint16_t), 1, g_ProcessMemFile );
}
inline
uint32_t MreadDWord (const uint32_t &offset)
{
uint32_t val;
fseek(g_ProcessMemFile, offset,SEEK_SET);
fread ( &val, sizeof(uint32_t), 1, g_ProcessMemFile );
return val;
}
inline
void MreadDWord (const uint32_t &offset, uint32_t &val)
{
fseek(g_ProcessMemFile, offset,SEEK_SET);
fread ( &val, sizeof(uint32_t), 1, g_ProcessMemFile );
}
inline
uint64_t MreadQuad (const uint32_t &offset)
{
uint64_t val;
fseek(g_ProcessMemFile, offset,SEEK_SET);
fread ( &val, sizeof(uint32_t), 1, g_ProcessMemFile );
return val;
}
inline
void MreadQuad (const uint32_t &offset, uint64_t &val)
{
fseek(g_ProcessMemFile, offset,SEEK_SET);
fread ( &val, sizeof(uint32_t), 1, g_ProcessMemFile );
}
inline
void Mread (const uint32_t &offset, const uint32_t &size, uint8_t *target)
{
fseek(g_ProcessMemFile, offset,SEEK_SET);
fread ( target, 1, size, g_ProcessMemFile );
}
inline
void MwriteDWord (uint32_t offset, uint32_t data)
{
ptrace(PTRACE_POKEDATA,g_ProcessHandle, offset, data);
}
// using these is expensive.
inline
void MwriteWord (uint32_t offset, uint16_t data)
{
uint32_t orig = MreadDWord(offset);
orig |= 0x0000FFFF;
orig &= data;
ptrace(PTRACE_POKEDATA,g_ProcessHandle, offset, orig);
}
inline
void MwriteByte (uint32_t offset, uint8_t data)
{
uint32_t orig = MreadDWord(offset);
orig |= 0x000000FF;
orig &= data;
ptrace(PTRACE_POKEDATA,g_ProcessHandle, offset, orig);
}
// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS
inline
bool Mwrite (uint32_t offset, uint32_t size, uint8_t *source)
{
uint32_t indexptr = 0;
while (size > 0)
{
// default: we push 4 bytes
if(size >= 4)
{
MwriteDWord(offset, *(uint32_t *) (source + indexptr));
offset +=4;
indexptr +=4;
size -=4;
}
// last is either three or 2 bytes
else if(size >= 2)
{
MwriteWord(offset, *(uint16_t *) (source + indexptr));
offset +=2;
indexptr +=2;
size -=2;
}
// finishing move
else if(size == 1)
{
MwriteByte(offset, *(uint8_t *) (source + indexptr));
return true;
}
}
}
inline
const std::string MreadCString (uint32_t offset)
{
std::string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = MreadByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}

@ -0,0 +1,156 @@
/*
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.
*/
/**
* DO NOT USE THIS FILE DIRECTLY! USE MemAccess.h INSTEAD!
*/
// let's hope this commented crap is never needed
/*
char buffer[256];
DWORD oldProtect = 0;
DWORD numRead = 0;
VirtualProtectEx( hProc, (LPVOID)0x77810F34, 256, PAGE_EXECUTE_READWRITE, &oldProtect );
ReadProcessMemory( hProc, (LPVOID)0x77810F34, buffer, 256, &numRead );
VirtualProtectEx( hProc, (LPVOID)0x77810F34, 256, oldProtect, NULL ); //restore the original protection when you're done
*/
// it would be possible to replace all this by macros
inline
uint8_t MreadByte (const uint32_t &offset)
{
uint8_t result;
ReadProcessMemory(g_ProcessHandle, (int*) offset, &result, sizeof(uint8_t), NULL);
return result;
}
inline
void MreadByte (const uint32_t &offset,uint8_t &result)
{
ReadProcessMemory(g_ProcessHandle, (int*) offset, &result, sizeof(uint8_t), NULL);
}
inline
uint16_t MreadWord (const uint32_t &offset)
{
uint16_t result;
ReadProcessMemory(g_ProcessHandle, (int*) offset, &result, sizeof(uint16_t), NULL);
return result;
}
inline
void MreadWord (const uint32_t &offset, uint16_t &result)
{
ReadProcessMemory(g_ProcessHandle, (int*) offset, &result, sizeof(uint16_t), NULL);
}
inline
uint32_t MreadDWord (const uint32_t &offset)
{
uint32_t result;
ReadProcessMemory(g_ProcessHandle, (int*) offset, &result, sizeof(uint32_t), NULL);
return result;
}
inline
void MreadDWord (const uint32_t &offset, uint32_t &result)
{
ReadProcessMemory(g_ProcessHandle, (int*) offset, &result, sizeof(uint32_t), NULL);
}
inline
uint64_t MreadQuad (const uint32_t &offset)
{
uint64_t result;
ReadProcessMemory(g_ProcessHandle, (int*) offset, &result, sizeof(uint64_t), NULL);
return result;
}
inline
void MreadQuad (const uint32_t &offset, uint64_t &result)
{
ReadProcessMemory(g_ProcessHandle, (int*) offset, &result, sizeof(uint64_t), NULL);
}
inline
void Mread (const uint32_t &offset, uint32_t size, uint8_t *target)
{
ReadProcessMemory(g_ProcessHandle, (int*) offset, target, size, NULL);
}
// WRITING
inline
void MwriteDWord (const uint32_t offset, uint32_t data)
{
WriteProcessMemory(g_ProcessHandle, (int*) offset, &data, sizeof(uint32_t), NULL);
}
// using these is expensive.
inline
void MwriteWord (uint32_t offset, uint16_t data)
{
WriteProcessMemory(g_ProcessHandle, (int*) offset, &data, sizeof(uint16_t), NULL);
}
inline
void MwriteByte (uint32_t offset, uint8_t data)
{
WriteProcessMemory(g_ProcessHandle, (int*) offset, &data, sizeof(uint8_t), NULL);
}
inline
bool Mwrite (uint32_t offset, uint32_t size, uint8_t *source)
{
WriteProcessMemory(g_ProcessHandle, (int*) offset, source, size, NULL);
}
///FIXME: reduce use of temporary objects
inline
const string MreadCString (const uint32_t &offset)
{
string temp;
char temp_c[256];
int counter = 0;
char r;
do
{
r = MreadByte(offset+counter);
temp_c[counter] = r;
counter++;
} while (r);
temp_c[counter] = 0;
temp = temp_c;
return temp;
}

@ -0,0 +1,661 @@
/*
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 "DFCommon.h"
// zlib helper functions for de/compressing files
#include "ZlibHelper.h"
#include "DfMapHeader.h"
// some bounds checking in debug mode. used in asserts
#define CheckBounds x < x_cell_count && x >= 0 && y < y_cell_count && y >= 0 && z < z_block_count && z >= 0
#define CheckBoundsXY x < x_cell_count && x >= 0 && y < y_cell_count && y >= 0
#define CheckBlockBounds x < x_block_count && x >= 0 && y < y_block_count && y >= 0 && z < z_block_count && z >= 0
// this expands into lots of ugly switch statement functions. some of them unused?, but kept for reference
#include "DFTileTypes.h"
// process vein vector into matgloss values...
void Block::collapseVeins()
{
// iterate through assigned veins
for( uint32_t i = 0; i < veins.size(); i++)
{
t_vein v = veins[i];
//iterate through vein assignment bit arrays - one for every row
for(uint32_t j = 0;j<16;j++)
{
//iterate through the bits
for (uint32_t k = 0; k< 16;k++)
{
// and the bit array with a one-bit mask, check if the bit is set
bool set = ((1 << k) & v.assignment[j]) >> k;
if(set)
{
material[k][j].type = Mat_Stone;
material[k][j].index = v.type;
}
}
}
}
}
DfMap::~DfMap()
{
clear();
}
/// TODO: make this sync
void DfMap::clear()
{
if(valid)
{
valid = false;
for(uint32_t i = 0; i < x_block_count*y_block_count*z_block_count;i++)
{
Block * b = block[i];
if(b!=NULL)
{
delete b;
}
}
delete[] block;
}
for (uint32_t i = eNorthWest; i< eBiomeCount;i++)
{
v_geology[i].clear();
//geodebug[i].clear();
//geoblockadresses[i] = 0;
//regionadresses[i] = 0;
}
for(uint32_t counter = Mat_Wood; counter < NUM_MATGLOSS_TYPES; counter++)
{
v_matgloss[counter].clear();
}
// delete buildings, clear vector
for(uint32_t i = 0; i < v_buildings.size(); i++)
{
delete v_buildings[i];
}
v_buildings.clear();
// delete vegetation, clear vector
for(uint32_t i = 0; i < v_trees.size(); i++)
{
delete v_trees[i];
}
v_trees.clear();
// clear construction vector
v_constructions.clear();
blocks_allocated = 0;
///FIXME: destroy all the extracted data here
}
void DfMap::getRegionCoords (uint32_t &x,uint32_t &y,uint32_t &z)
{
x= regionX;
y= regionY;
z= regionZ;
}
void DfMap::setRegionCoords (uint32_t x,uint32_t y,uint32_t z)
{
regionX = x;
regionY = y;
regionZ = z;
}
void DfMap::allocBlockArray(uint32_t x,uint32_t y, uint32_t z)
{
clear();
x_block_count = x;
y_block_count = y;
z_block_count = z;
updateCellCount();
block = new Block*[x_block_count*y_block_count*z_block_count];
for (uint32_t i = 0; i < x_block_count*y_block_count*z_block_count; i++ )
{
block[i] = NULL;
}
blocks_allocated = 0;
valid = true;
}
DfMap::DfMap(uint32_t x, uint32_t y, uint32_t z)
{
valid = false;
allocBlockArray(x,y,z);
}
DfMap::DfMap(string FileName)
{
valid = false;
valid = load( FileName);
}
bool DfMap::isValid ()
{
return valid;
}
Block * DfMap::getBlock (uint32_t x,uint32_t y,uint32_t z)
{
if(isValid())
{
return block[x*y_block_count*z_block_count + y*z_block_count + z];
}
return NULL;
}
vector<t_building *> * DfMap::getBlockBuildingsVector(uint32_t x,uint32_t y,uint32_t z)
{
Block * b = getBlock(x,y,z);
if(b)
{
return &b->v_buildings;
}
return NULL;
}
vector<t_tree_desc *> * DfMap::getBlockVegetationVector(uint32_t x,uint32_t y,uint32_t z)
{
Block * b = getBlock(x,y,z);
if(b)
{
return &b->v_trees;
}
return NULL;
}
t_tree_desc *DfMap::getTree (uint32_t x, uint32_t y, uint32_t z)
{
for(uint32_t i = 0; i< v_trees.size();i++)
{
if(x == v_trees[i]->x
&& y == v_trees[i]->y
&& z == v_trees[i]->z)
{
return v_trees[i];
}
}
return 0;
}
t_building *DfMap::getBuilding (uint32_t x, uint32_t y, uint32_t z)
{
for(uint32_t i = 0; i< v_buildings.size();i++)
{
if(x >= v_buildings[i]->x1 && x <= v_buildings[i]->x2
&& y >= v_buildings[i]->y1 && y <= v_buildings[i]->y2
&& z == v_buildings[i]->z)
{
return v_buildings[i];
}
}
return 0;
}
Block * DfMap::allocBlock (uint32_t x,uint32_t y,uint32_t z)
{
if(isValid())
{
if(block[x*y_block_count*z_block_count + y*z_block_count + z])
{
return block[x*y_block_count*z_block_count + y*z_block_count + z];
}
Block *b = new Block;
block[x*y_block_count*z_block_count + y*z_block_count + z] = b;
blocks_allocated++;
return b;
}
return NULL;
}
void DfMap::updateCellCount()
{
x_cell_count = x_block_count * BLOCK_SIZE;
y_cell_count = y_block_count * BLOCK_SIZE;
z_cell_count = z_block_count;
}
void DfMap::applyGeoMatgloss(Block * b)
{
// load layer matgloss
for(int x_b = 0; x_b < BLOCK_SIZE; x_b++)
{
for(int y_b = 0; y_b < BLOCK_SIZE; y_b++)
{
int geolayer = b->designation[x_b][y_b].bits.geolayer_index;
int biome = b->designation[x_b][y_b].bits.biome;
b->material[x_b][y_b].type = Mat_Stone;
b->material[x_b][y_b].index = v_geology[b->RegionOffsets[biome]][geolayer];
}
}
}
uint8_t DfMap::getLiquidLevel(uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return b->designation[x2][y2].bits.flow_size;
}
return 0;
}
uint16_t DfMap::getTileType(uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return b->tile_type[x2][y2];
}
if(isTileSky(x,y,z,x2,y2))
{
return 32;
}
return -1;
}
uint16_t DfMap::getTileType(uint32_t x, uint32_t y, uint32_t z, uint32_t blockX, uint32_t blockY)
{
assert(CheckBlockBounds);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return b->tile_type[blockX][blockY];
}
if(isTileSky(x,y,z,blockX,blockY))
{
return 32;
}
return -1;
}
uint32_t DfMap::getDesignations(uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return b->designation[x2][y2].whole;
}
return -1;
}
bool DfMap::isBlockInitialized(uint32_t x, uint32_t y, uint32_t z)
{
// because of the way DfMap is done, more than one check must be made.
return getBlock(x,y,z) != NULL;
}
uint32_t DfMap::getOccupancies(uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return b->occupancy[x2][y2].whole;
}
return -1;
}
void DfMap::getGeoRegion (uint32_t x, uint32_t y, uint32_t z, int32_t& geoX, int32_t& geoY)
{
assert(CheckBoundsXY);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
int biome = b->designation[x2][y2].bits.biome;
int BiomeOffset = b->RegionOffsets[biome];
int16_t X_biomeB = (regionX / 16) + (BiomeOffset % 3) - 1;
int16_t Y_biomeB = (regionY / 16) + (BiomeOffset / 3) - 1;
if(X_biomeB < 0) X_biomeB = 0;
if(Y_biomeB < 0) Y_biomeB = 0;
if( (uint32_t)X_biomeB >= worldSizeX)
{
X_biomeB = worldSizeX - 1;
}
if( (uint32_t)Y_biomeB >= worldSizeY)
{
Y_biomeB = worldSizeY - 1;
}
geoX = X_biomeB;
geoY = Y_biomeB;
}
else
{
geoX = regionX / 16;
geoY = regionY / 16;
}
}
t_matglossPair DfMap::getMaterialPair (uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return b->material[x2][y2];
}
t_matglossPair fail = {-1,-1};
return fail;
};
// this is what the vein structures say it is
string DfMap::getGeoMaterialString (uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return getMaterialString(b->material[x2][y2].type, b->material[x2][y2].index);
}
string fallback = "UNKNOWN";
return fallback;
}
string DfMap::getMaterialTypeString (uint32_t type)
{
string ret = "";
switch (type)
{
case 0:
ret += "wood";
break;
case 1:
ret += "stone/soil";
break;
case 2:
ret += "metal";
break;
case 3:
ret += "plant";
break;
case 10:
ret += "leather";
break;
case 11:
ret += "silk cloth";
break;
case 12:
ret += "plant thread cloth";
break;
case 13: // green glass
ret += "green glass";
break;
case 14: // clear glass
ret += "clear glass";
break;
case 15: // crystal glass
ret += "crystal glass";
break;
case 17:
ret += "ice";
break;
case 18:
ret += "charcoal";
break;
case 19:
ret += "potash";
break;
case 20:
ret += "ashes";
break;
case 21:
ret += "pearlash";
break;
case 24:
ret += "soap";
break;
default:
ret += "unknown";
break;
}
return ret;
}
string DfMap::getMaterialString (uint32_t type, uint32_t index)
{
if(index != 65535 && type >= 0 && type < NUM_MATGLOSS_TYPES)
{
if(index < v_matgloss[type].size())
{
return v_matgloss[type][index];
}
else
{
string fallback = "ERROR";
return fallback;
}
}
string fallback = "UNKNOWN";
return fallback;
}
uint16_t DfMap::getNumMatGloss(uint16_t type)
{
return v_matgloss[type].size();
}
string DfMap::getBuildingTypeName(uint32_t index)
{
if(index < v_buildingtypes.size())
{
return v_buildingtypes[index];
}
return string("error");
}
string DfMap::getMatGlossString(uint16_t type,uint16_t index)
{
if(index < v_matgloss[type].size())
{
return v_matgloss[type][index];
}
return string("error");
}
// matgloss part of the designation
unsigned int DfMap::getGeolayerIndex (uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return b->designation[x2][y2].bits.geolayer_index;
}
return -1;
}
// matgloss part of the designation
unsigned int DfMap::getBiome (uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return b->designation[x2][y2].bits.biome;
}
return -1;
}
bool DfMap::isHidden (uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return (b->designation[x2][y2].bits.hidden);
}
return false;
}
bool DfMap::isSubterranean (uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return (b->designation[x2][y2].bits.subterranean);
}
if(isTileSky( x, y, z, x2, y2))
{
return false;
}
return true;
}
// x,y,z - coords of block
// blockX,blockY - coords of tile inside block
bool DfMap::isTileSky(uint32_t x, uint32_t y, uint32_t z, uint32_t blockX, uint32_t blockY)
{
assert(CheckBounds);
Block *b;
// trace down through blocks until we hit an inited one or the base
for (int i = z; i>= 0;i--)
{
b = getBlock(x,y,i);
if(b)
{
// is the inited block open to the sky?
return b->designation[blockX][blockY].bits.skyview;
}
}
// we hit base
return false;
}
// is the sky above this tile visible?
bool DfMap::isSkyView (uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return (b->designation[x2][y2].bits.skyview);
}
if(isTileSky(x,y,z,x2,y2))
{
return true;
}
return false;
}
// is there light in this tile?
bool DfMap::isSunLit (uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return (b->designation[x2][y2].bits.light);
}
return false;
}
bool DfMap::isMagma (uint32_t x, uint32_t y, uint32_t z)
{
assert(CheckBounds);
uint32_t x2, y2;
convertToDfMapCoords(x, y, x, y, x2, y2);
Block *b = getBlock(x,y,z);
if(b != NULL)
{
return (b->designation[x2][y2].bits.liquid_type);
}
return false;
}

@ -0,0 +1,204 @@
/*
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 DFMAP_H_INCLUDED
#define DFMAP_H_INCLUDED
#define BLOCK_SIZE 16
class DfMapHeader;
class Block
{
public:
// where does the Block come from?
uint32_t origin;
// generic tile type. determines how the tile behaves ingame
uint16_t tile_type[BLOCK_SIZE][BLOCK_SIZE];
t_designation designation[BLOCK_SIZE][BLOCK_SIZE];
t_occupancy occupancy[BLOCK_SIZE][BLOCK_SIZE];
// veins
vector <t_vein> veins;
t_matglossPair material[BLOCK_SIZE][BLOCK_SIZE];
vector<t_building*> v_buildings;
vector<t_tree_desc*> v_trees;
void collapseVeins();
/**
// region offset modifiers... what a hack.
// here we have double indexed offset into regions.
// once inside t_designation, pointing into this, second time from here as a index modifier into region array (2d)
// disassembled code where it's used follows. biome is biome from t_designation
biome_stuffs = *(_BYTE *)((char)biome + offset_Block + 0x1D84);
biome_stuffs_mod3 = biome_stuffs % 3;
biome_stuffs_div3 = biome_stuffs / 3;
biome_stuffs_mod3_ = biome_stuffs_mod3;
if ( !biome_stuffs_mod3_ )
--*(_WORD *)X_stuff;
if ( biome_stuffs_mod3_ == 2 )
++*(_WORD *)X_stuff;
if ( !biome_stuffs_div3 )
--*(_WORD *)Y_stuff_;
if ( biome_stuffs_div3 == 2 )
++*(_WORD *)Y_stuff_;
*/
uint8_t RegionOffsets[16];// idk if the length is right here
};
/**
* This class can load and save DF maps
*/
class DfMap
{
private:
// allow extractor direct access to our data, avoid call lag and lots of self-serving methods
friend class Extractor;
Block **block;
uint32_t blocks_allocated;
bool valid;
// converts the (x,y,z) cell coords to internal coords
// out_y, out_x - block coords
// out_y2, out_x2 - cell coords in that block
inline void convertToDfMapCoords(uint32_t x, uint32_t y, uint32_t &out_x, uint32_t &out_y, uint32_t &out_x2, uint32_t &out_y2)
{
out_x = x / BLOCK_SIZE;
out_x2 = x % BLOCK_SIZE;
out_y = y / BLOCK_SIZE;
out_y2 = y % BLOCK_SIZE;
};
void allocBlockArray(uint32_t x,uint32_t y, uint32_t z);
void updateCellCount();
bool loadVersion1(FILE * Decompressed,DfMapHeader & h);
bool writeVersion1(FILE * SaveFile);
bool loadMatgloss2(FILE * Decompressed);
bool loadBlocks2(FILE * Decompressed,DfMapHeader & h);
bool loadRegion2(FILE * Decompressed);
bool loadVersion2(FILE * Decompressed,DfMapHeader & h);
void writeMatgloss2(FILE * SaveFile);
void writeBlocks2(FILE * SaveFile);
void writeRegion2(FILE * SaveFile);
bool writeVersion2(FILE * SaveFile);
uint32_t regionX;
uint32_t regionY;
uint32_t regionZ;
///FIXME: these belong to some world structure
uint32_t worldSizeX;
uint32_t worldSizeY;
vector<uint16_t> v_geology[eBiomeCount];
vector<string> v_matgloss[NUM_MATGLOSS_TYPES];
vector<string> v_buildingtypes;
vector<t_construction> v_constructions;
vector<t_building*> v_buildings;
vector<t_tree_desc*> v_trees;
unsigned x_block_count, y_block_count, z_block_count; // block count
unsigned x_cell_count, y_cell_count, z_cell_count; // cell count
public:
DfMap();
DfMap(uint32_t x, uint32_t y, uint32_t z);
DfMap(string file_name);
~DfMap();
/// TODO: rework matgloss
void applyGeoMatgloss(Block * b);
// accessing vectors of materials
uint16_t getNumMatGloss(uint16_t type);
string getMaterialTypeString (uint32_t type);
string getMatGlossString(uint16_t type, uint16_t index);
// accessing vectors of building types
uint32_t getNumBuildingTypes();
string getBuildingTypeName(uint32_t index);
bool isValid();
bool load(string FilePath);
bool write(string FilePath);
void clear();
Block* getBlock(uint32_t x, uint32_t y, uint32_t z);
Block* allocBlock(uint32_t x, uint32_t y, uint32_t z);
bool deallocBlock(uint32_t x, uint32_t y, uint32_t z);
vector<t_building *> * getBlockBuildingsVector(uint32_t x,uint32_t y,uint32_t z);
vector<t_tree_desc *> * getBlockVegetationVector(uint32_t x,uint32_t y,uint32_t z);
inline unsigned int getXBlocks() { return x_block_count; }
inline unsigned int getYBlocks() { return y_block_count; }
inline unsigned int getZBlocks() { return z_block_count; }
bool isTileSky(uint32_t x, uint32_t y, uint32_t z, uint32_t blockX, uint32_t blockY);
uint16_t getTileType(uint32_t x, uint32_t y, uint32_t z);
uint16_t getTileType(uint32_t x, uint32_t y, uint32_t z, uint32_t blockX, uint32_t blockY);
uint32_t getDesignations(uint32_t x, uint32_t y, uint32_t z);
uint32_t getOccupancies(uint32_t x, uint32_t y, uint32_t z);
// get tile material
t_matglossPair getMaterialPair (uint32_t x, uint32_t y, uint32_t z);
string getGeoMaterialString (uint32_t x, uint32_t y, uint32_t z);
string getMaterialString (uint32_t type, uint32_t index);
// get coords of region used for materials
void getGeoRegion (uint32_t x, uint32_t y, uint32_t z, int32_t& geoX, int32_t& geoY);
// matgloss part of the designation
uint32_t getGeolayerIndex (uint32_t x, uint32_t y, uint32_t z);
void getRegionCoords (uint32_t &x,uint32_t &y,uint32_t &z);
void setRegionCoords (uint32_t x,uint32_t y,uint32_t z);
// what kind of building is here?
//uint16_t getBuilding (uint32_t x, uint32_t y, uint32_t z);
t_building *getBuilding (uint32_t x, uint32_t y, uint32_t z);
t_tree_desc *getTree (uint32_t x, uint32_t y, uint32_t z);
unsigned int getBiome (uint32_t x, uint32_t y, uint32_t z);
int picktexture(int);
/*
bool isOpenTerrain(int);
bool isStairTerrain(int);
bool isRampTerrain(int);
bool isFloorTerrain(int);
bool isWallTerrain(int);
*/
bool isBlockInitialized(uint32_t x, uint32_t y, uint32_t z);
bool isHidden (uint32_t x, uint32_t y, uint32_t z);
bool isSubterranean (uint32_t x, uint32_t y, uint32_t z);
bool isSkyView (uint32_t x, uint32_t y, uint32_t z);
bool isSunLit (uint32_t x, uint32_t y, uint32_t z);
bool isMagma (uint32_t x, uint32_t y, uint32_t z);
uint8_t getLiquidLevel(uint32_t x, uint32_t y, uint32_t z);
};
#endif // DFMAP_H_INCLUDED

@ -0,0 +1,41 @@
/*
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 DF_MAP_HEADER_H
#define DF_MAP_HEADER_H
static const char dmh_id[] = "!!URIST!!";
static const uint8_t dmh_ver = 1U;
// a header for save files
struct DfMapHeader
{
char identifier[10]; // !!URIST!!
uint8_t version; // DfMap/Header version; current: 1
uint32_t reserved; // reserved 4 bytes
};
#endif // DF_MAP_HEADER_H

@ -0,0 +1,433 @@
/*
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.
*/
// Extractor
#include "DFCommon.h"
using namespace std;
#include "Extract.h"
#include "DFDataModel.h"
#include "DFMemInfo.h"
Extractor::Extractor()
{
df_map = NULL; // important, null pointer means we don't have a map loaded
}
Extractor::~Extractor()
{
if(df_map !=NULL )
{
delete df_map;
}
}
bool Extractor::dumpMemory( string path_to_xml)
{
// create process manager, get first process
ProcessManager pm(path_to_xml);
if(!pm.findProcessess())
{
fprintf(stderr,"Can't find any suitable DF process\n");
return false;
}
// attach to process
printf("Attempting to Attach Process\n");
///FIXME: this won't do.
Process * p = pm[0];
DataModel * dm = p->getDataModel();
if(!p->attach())
{
printf("Could not Attach Process, Aborting\n");
return false; // couldn't attach to process, no go
}
printf("Process succesfully Attached\n");
memory_info* offset_descriptor = p->getDescriptor();
uint32_t map_loc, // location of the X array
temp_loc, // block location
temp_locx, // iterator for the X array
temp_locy, // iterator for the Y array
temp_locz; // iterator for the Z array
unsigned blocks_read = 0U;
// Read Map Data Blocks
int map_offset = offset_descriptor->getAddress("map_data");;
int x_count_offset = offset_descriptor->getAddress("x_count");
int y_count_offset = offset_descriptor->getAddress("y_count");
int z_count_offset = offset_descriptor->getAddress("z_count");
int tile_type_offset = offset_descriptor->getOffset("type");
int designation_offset = offset_descriptor->getOffset("designation");
int occupancy_offset = offset_descriptor->getOffset("occupancy");
int biome_stuffs = offset_descriptor->getOffset("biome_stuffs");
// layers
int region_x_offset = offset_descriptor->getAddress("region_x");
int region_y_offset = offset_descriptor->getAddress("region_y");
int region_z_offset = offset_descriptor->getAddress("region_z");
int world_offset = offset_descriptor->getAddress("world");
int world_regions_offset = offset_descriptor->getOffset("w_regions_arr");
int region_size = offset_descriptor->getHexValue("region_size");
int region_geo_index_offset = offset_descriptor->getOffset("region_geo_index_off");
int world_geoblocks_offset = offset_descriptor->getOffset("w_geoblocks");
int world_size_x = offset_descriptor->getOffset("world_size_x");
int world_size_y = offset_descriptor->getOffset("world_size_y");
int geolayer_geoblock_offset = offset_descriptor->getOffset("geolayer_geoblock_offset");
// veins
int veinvector = offset_descriptor->getOffset("v_vein");
int veinsize = offset_descriptor->getHexValue("v_vein_size");
int vegetation = offset_descriptor->getAddress("vegetation");
int tree_desc_offset = offset_descriptor->getOffset("tree_desc_offset");
// constructions
int constructions = offset_descriptor->getAddress("constructions");
// buildings
int buildings = offset_descriptor->getAddress("buildings");
/// TODO: what about building shape and orientation?
// matgloss
int matgloss_address = offset_descriptor->getAddress("matgloss");
int matgloss_skip = offset_descriptor->getHexValue("matgloss_skip");
bool have_geology = false;
printf("Map offset: 0x%.8X\n", map_offset);
map_loc = MreadDWord(map_offset);
if (!map_loc)
{
printf("Could not find DF map information in memory, Aborting\n");
return false;
}
printf("Map data Found at: 0x%.8X\n", map_loc);
if(df_map != NULL)
{
delete df_map;
}
df_map = new DfMap(MreadDWord(x_count_offset),MreadDWord(y_count_offset),MreadByte(z_count_offset));
// read matgloss data from df if we can
RawType matglossRawMapping[] = {Mat_Wood, Mat_Stone, Mat_Metal, Mat_Plant};
if(matgloss_address && matgloss_skip)
{
uint32_t addr = matgloss_address;
uint32_t counter = Mat_Wood;
for(; counter < NUM_MATGLOSS_TYPES; addr += matgloss_skip, counter++)
{
// get vector of matgloss pointers
DfVector p_matgloss = dm->readVector(addr, 4);
// iterate over it
for (uint32_t i = 0; i< p_matgloss.getSize();i++)
{
uint32_t temp;
string tmpstr;
// read the matgloss pointer from the vector into temp
p_matgloss.read((uint32_t)i,(uint8_t *)&temp);
// read the string pointed at by temp
tmpstr = dm->readSTLString(temp);
// store it in the block
df_map->v_matgloss[matglossRawMapping[counter]].push_back(tmpstr);
printf("%d = %s\n",i,tmpstr.c_str());
}
}
}
if(region_x_offset && region_y_offset && region_z_offset)
{
// we have offsets for region coordinates, get them.
df_map->setRegionCoords(MreadDWord(region_x_offset),MreadDWord(region_y_offset),MreadDWord(region_z_offset));
// extract layer geology data. we need all these to do that
if(world_size_x && world_size_y && world_offset && world_regions_offset && world_geoblocks_offset && region_size && region_geo_index_offset && geolayer_geoblock_offset)
{
// get world size
int worldSizeX = MreadWord(world_offset + world_size_x);
int worldSizeY = MreadWord(world_offset + world_size_y);
df_map->worldSizeX = worldSizeX;
df_map->worldSizeY = worldSizeY;
printf("World size. X=%d Y=%d\n",worldSizeX,worldSizeY);
// get pointer to first part of 2d array of regions
uint32_t regions = MreadDWord(world_offset + world_regions_offset);
printf("regions. Offset=%d\n",regions);
// read the 9 surrounding regions
DfVector geoblocks = dm->readVector(world_offset + world_geoblocks_offset,4);
// iterate over surrounding biomes. make sure we don't fall off the world
for(int i = eNorthWest; i< eBiomeCount; i++)
{
// check bounds, fix them if needed
int bioRX = df_map->regionX / 16 + (i%3) - 1;
if( bioRX < 0) bioRX = 0;
if( bioRX >= worldSizeX) bioRX = worldSizeX - 1;
int bioRY = df_map->regionY / 16 + (i/3) - 1;
if( bioRY < 0) bioRY = 0;
if( bioRY >= worldSizeY) bioRY = worldSizeY - 1;
/// TODO: encapsulate access to multidimensional arrays.
// load region stuff here
uint32_t geoX = MreadDWord(regions + bioRX*4);// get pointer to column of regions
// geoX = base
// bioRY = index
// region_size = size of array objects
// region_geo_index_off = offset into the array object
uint16_t geoindex = MreadWord(geoX + bioRY*region_size + region_geo_index_offset);
uint32_t geoblock_off;
// get the geoblock from the geoblock vector using the geoindex
geoblocks.read(geoindex,(uint8_t *) &geoblock_off);
// get the layer pointer vector :D
DfVector geolayers = dm->readVector(geoblock_off + geolayer_geoblock_offset , 4); // let's hope
// make sure we don't load crap
assert(geolayers.getSize() > 0 && geolayers.getSize() <= 16);
for(uint32_t j = 0;j< geolayers.getSize();j++)
{
int geol_offset;
// read pointer to a layer
geolayers.read(j, (uint8_t *) & geol_offset);
// read word at pointer + 2, store in our geology vectors
df_map->v_geology[i].push_back(MreadWord(geol_offset + 2));
}
}
have_geology = true;
}
}
else
{
// crap, can't get the real layer materials
df_map->setRegionCoords(0,0,0);
}
//read the memory from the map blocks
for(uint32_t x = 0; x < df_map->x_block_count; x++)
{
temp_locx = map_loc + ( 4 * x );
temp_locy = MreadDWord(temp_locx);
for(uint32_t y = 0; y < df_map->y_block_count; y++)
{
temp_locz = MreadDWord(temp_locy);
temp_locy += 4;
for(uint32_t z = 0; z < df_map->z_block_count; z++)
{
temp_loc = MreadDWord(temp_locz);
temp_locz += 4;
if (temp_loc)
{
Block * b = df_map->allocBlock(x,y,z);
b->origin = temp_loc; // save place of block in DF's memory for later
Mread(
/*Uint32 offset*/ temp_loc + tile_type_offset,
/*Uint32 size*/ sizeof(uint16_t)*BLOCK_SIZE*BLOCK_SIZE,
/*void *target*/ (uint8_t *)&b->tile_type
);
Mread(
/*Uint32 offset*/ temp_loc + designation_offset,
/*Uint32 size*/ sizeof(uint32_t)*BLOCK_SIZE*BLOCK_SIZE,
/*void *target*/ (uint8_t *)&b->designation
);
Mread(
/*Uint32 offset*/ temp_loc + occupancy_offset,
/*Uint32 size*/ sizeof(uint32_t)*BLOCK_SIZE*BLOCK_SIZE,
/*void *target*/ (uint8_t *)&b->occupancy
);
// set all materials to -1.
memset(b->material, -1, sizeof(int16_t) * 256);
if(biome_stuffs) // we got biome stuffs! we can try loading matgloss from here
{
Mread(
/*Uint32 offset*/ temp_loc + biome_stuffs,
/*Uint32 size*/ sizeof(uint8_t)*16,
/*void *target*/ (uint8_t *)&b->RegionOffsets
);
// if we have geology, we can use the geolayers to determine materials
if(have_geology)
{
df_map->applyGeoMatgloss(b);
}
}
else
{
// can't load offsets, substitute local biome everywhere
memset(b->RegionOffsets,eHere,sizeof(b->RegionOffsets));
}
// load veins from the game
if(veinvector && veinsize)
{
assert(sizeof(t_vein) == veinsize);
// veins are stored as a vector of pointers to veins .. at least in df 40d11 on linux
/*pointer is 4 bytes! we work with a 32bit program here, no matter what architecture we compile khazad for*/
DfVector p_veins = dm->readVector(temp_loc + veinvector, 4);
// read all veins
for (uint32_t i = 0; i< p_veins.getSize();i++)
{
t_vein v;
uint32_t temp;
// read the vein pointer from the vector
p_veins.read((uint32_t)i,(uint8_t *)&temp);
// read the vein data (dereference pointer)
Mread(temp, veinsize, (uint8_t *)&v);
// store it in the block
b->veins.push_back(v);
}
b->collapseVeins(); // collapse *our* vein vector into vein matgloss data
}
}
}
}
}
// read constructions, apply immediately.
if(constructions)
{
// read the constructions vector
DfVector p_cons = dm->readVector(constructions,4);
// iterate
for (uint32_t i = 0; i< p_cons.getSize();i++)
{
uint32_t temp;
t_construction c;
t_construction_df40d c_40d;
// read pointer from vector at position
p_cons.read((uint32_t)i,(uint8_t *)&temp);
//read construction from memory
Mread(temp, sizeof(t_construction_df40d), (uint8_t *)&c_40d);
// stupid apply. this will probably be removed later
Block * b = df_map->getBlock(c_40d.x/16,c_40d.y/16,c_40d.z);
b->material[c_40d.x%16][c_40d.y%16] = c_40d.material;
//b->material[c_40d.x%16][c_40d.y%16].index = c_40d.material.index;
// transform
c.x = c_40d.x;
c.y = c_40d.y;
c.z = c_40d.z;
c.material = c_40d.material;
// store for save/load
df_map->v_constructions.push_back(c);
}
}
if(buildings)
{
// fill the building type vector first
offset_descriptor->copyBuildings(df_map->v_buildingtypes);
DfVector p_bld = dm->readVector(buildings,4);
for (uint32_t i = 0; i< p_bld.getSize();i++)
{
uint32_t temp;
t_building * bld = new t_building;
t_building_df40d bld_40d;
// read pointer from vector at position
p_bld.read((uint32_t)i,(uint8_t *)&temp);
//read construction from memory
Mread(temp, sizeof(t_building_df40d), (uint8_t *)&bld_40d);
// transform
int32_t type = -1;
offset_descriptor->resolveClassId(temp, type);
bld->vtable = bld_40d.vtable;
bld->type = type;
bld->x1 = bld_40d.x1;
bld->x2 = bld_40d.x2;
bld->y1 = bld_40d.y1;
bld->y2 = bld_40d.y2;
bld->z = bld_40d.z;
bld->material = bld_40d.material;
// store for save/load. will need more processing.
df_map->v_buildings.push_back(bld);
///FIXME: delete created building structs
// save buildings in a block for later display
Block * b = df_map->getBlock(bld->x1/16,bld->y1/16,bld->z);
b->v_buildings.push_back(bld);
}
}
if(vegetation && tree_desc_offset)
{
DfVector p_tree = dm->readVector(vegetation,4);
for (uint32_t i = 0; i< p_tree.getSize();i++)
{
uint32_t temp;
t_tree_desc * tree = new t_tree_desc;
// read pointer from vector at position
p_tree.read((uint32_t)i,(uint8_t *)&temp);
//read construction from memory
Mread(temp + tree_desc_offset, sizeof(t_tree_desc), (uint8_t *)tree);
// fix bad stuff
if(tree->material.type == 2) tree->material.type = 3;
// store for save/load. will need more processing.
df_map->v_trees.push_back(tree);
// save buildings in a block for later display
Block * b = df_map->getBlock(tree->x/16,tree->y/16,tree->z);
b->v_trees.push_back(tree);
}
}
printf("Blocks read into memory: %d\n", blocks_read);
p->detach();
return true;
}
// wrappers!
bool Extractor::loadMap(string FileName)
{
if(df_map == NULL)
{
df_map = new DfMap(FileName);
}
else
{
df_map->load(FileName);
}
return df_map->isValid();
}
bool Extractor::writeMap(string FileName)
{
if(df_map == NULL)
{
return false;
}
return df_map->write(FileName);
}
bool Extractor::isMapLoaded()
{
if(df_map != NULL)
{
if(df_map->isValid())
{
return true;
}
}
return false;
}

@ -0,0 +1,51 @@
/*
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.
*/
/* Memory research
http://dwarffortresswiki.net/index.php/User:Rick/memory.ini#A_table_of_available_settings
http://dwarffortresswiki.net/index.php/User:Rick/Memory_research#Tile_Block
http://dwarffortresswiki.net/index.php/User:AzureLightning/Memory_research
http://dwarffortresswiki.net/index.php/User:Iluxan/Memory_research
*/
#ifndef EXTRACT_HEADER
#define EXTRACT_HEADER
class DfMap;
class Extractor
{
protected:
DfMap *df_map; // DF extracted map structure
public:
bool Init();
Extractor();
~Extractor();
bool loadMap(string FileName);
bool writeMap(string FileName);
bool isMapLoaded();
DfMap *getMap() {return df_map;};
bool dumpMemory( string path_to_xml);
};
#endif // EXTRACT_HEADER

@ -0,0 +1,188 @@
/*
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 "DFCommon.h"
#include "DfMap.h"
#include "DfMapHeader.h"
#include "ZlibHelper.h"
bool DfMap::write(string FilePath)
{
FILE *SaveFile;
SaveFile = fopen(FilePath.c_str(),"wb");
DfMapHeader df_map_header;
if(SaveFile == NULL)
{
printf("Can\'t create file for write.\n");
return false;
}
else
{
// gather information to fill dfmapheader
strcpy(df_map_header.identifier, dmh_id);
df_map_header.version = dmh_ver;
df_map_header.reserved = 0/*sizeof(DfMapHeader)*/;
// save map header
fwrite(&df_map_header, sizeof(DfMapHeader), 1, SaveFile);
// save map
writeVersion1(SaveFile);
}
// reopen file for reading
freopen (FilePath.c_str(),"rb",SaveFile);
if(SaveFile == NULL)
{
printf("Can\'t create file for read.\n");
return false;
}
FILE *SaveCompressedFile;
string CompressedFilePath = FilePath + ".comp";
SaveCompressedFile = fopen(CompressedFilePath.c_str(),"wb");
if(SaveCompressedFile == NULL)
{
printf("Can\'t create a compressed file for write\n");
return false;
}
// compress
printf("Compressing... ");
int ret = def(SaveFile, SaveCompressedFile, Z_BEST_COMPRESSION);
if (ret != Z_OK)
{
zerr(ret);
}
printf("DONE\n");
fclose(SaveFile);
fclose(SaveCompressedFile);
remove(FilePath.c_str());
rename(CompressedFilePath.c_str(), FilePath.c_str());
return true;
}
bool DfMap::load(string FilePath)
{
string DecompressedFilePath = FilePath + ".decomp";
FILE *ToDecompress;
FILE *Decompressed;
DfMapHeader df_map_header;
bool isok = false;
// open file for writing decompressed data
Decompressed = fopen(DecompressedFilePath.c_str(), "wb");
if (Decompressed == NULL)
{
printf("Can\'t open a decompressed file for write.\n");
return false;
}
// open compressed file
ToDecompress = fopen(FilePath.c_str(),"rb");
if (ToDecompress == NULL)
{
printf("Can\'t open file for read.\n");
return false;
}
// decompress
printf("Decompressing... ");
int ret = inf(/*source*/ToDecompress,/*destination*/Decompressed);
printf("DONE\n");
if (ret != Z_OK)
{
zerr(ret);
}
// OK, close file with compressed data
fclose(ToDecompress);
// reopen decompressed file for reading
freopen(DecompressedFilePath.c_str(), "rb", Decompressed);
if (Decompressed == NULL)
{
printf("Can\'t create decompressed file for read.\n");
return false;
}
// check, if the file is big enough to contain the header
fseek(Decompressed, 0, SEEK_END);
if (ftell(Decompressed) < (int32_t)sizeof(DfMapHeader))
{
printf("This Khazad map file is corrupted - file too small.\n");
return false;
}
// read the header
fseek(Decompressed, 0, SEEK_SET);
fread(&df_map_header, sizeof(DfMapHeader), 1, Decompressed);
// check, if it's a Khazad map file
if (strcmp(df_map_header.identifier,dmh_id) != 0)
{
printf("This file is not a Khazad map file.\n");
return false;
}
// ALERT: flush all map data. This is very important.
clear();
switch(df_map_header.version)
{
/*
Basic format without matgloss. Kept for compatibility reasons.
Saved from version 0.0.5
*/
case 1:
isok = loadVersion1(Decompressed, df_map_header);
break;
/*
v2 format
Saved from some SVN version. this format is dead
*/
case 2:
//isok = loadVersion2(Decompressed, df_map_header);
isok = false;
break;
default:
printf("Unknown Khazad map file version(%3d).\n", df_map_header.version);
isok = false;
break;
}
// close decompressed file and delete it
fclose(Decompressed);
remove(DecompressedFilePath.c_str());
return isok;
}

@ -0,0 +1,106 @@
/*
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 "DFCommon.h"
#include "DfMap.h"
#include "DfMapHeader.h"
#include "ZlibHelper.h"
// LOAD v1 BLOCKS
bool DfMap::loadVersion1(FILE * Decompressed,DfMapHeader & h)
{
uint32_t x, y, z;
uint32_t tile_block_count; // how many tile blocks to read from the data location
// load new size information
fread(&tile_block_count, sizeof(uint32_t), 1, Decompressed);
fread(&x_block_count, sizeof(uint32_t), 1, Decompressed);
fread(&y_block_count, sizeof(uint32_t), 1, Decompressed);
fread(&z_block_count, sizeof(uint32_t), 1, Decompressed);
// make sure those size variables are in sync
updateCellCount();
// alloc new space for our new size
allocBlockArray(x_block_count,y_block_count,z_block_count);
// let's load the blocks
for (uint32_t tile_block = 0U; tile_block < tile_block_count; ++tile_block)
{
// block position - we can omit empty blocks this way
fread(&x, sizeof(uint32_t), 1, Decompressed);
fread(&y, sizeof(uint32_t), 1, Decompressed);
fread(&z, sizeof(uint32_t), 1, Decompressed);
Block * b = allocBlock(x,y,z);
// read data
fread(&b->tile_type, sizeof(b->tile_type), 1, Decompressed);
fread(&b->designation, sizeof(b->designation), 1, Decompressed);
fread(&b->occupancy, sizeof(b->occupancy), 1, Decompressed);
memset(b->material, -1, sizeof(b->material));
// can't load offsets, substitute local biome everywhere
memset(b->RegionOffsets,eHere,sizeof(b->RegionOffsets));
}
printf("Blocks read into memory: %d\n", tile_block_count);
return true;
}
// SAVE v1 BLOCKS
bool DfMap::writeVersion1(FILE * SaveFile)
{
uint32_t x, y, z;
// write size information - total blocks and map size
fwrite(&blocks_allocated, sizeof(uint32_t), 1, SaveFile);
fwrite(&x_block_count, sizeof(uint32_t), 1, SaveFile);
fwrite(&y_block_count, sizeof(uint32_t), 1, SaveFile);
fwrite(&z_block_count, sizeof(uint32_t), 1, SaveFile);
// write each non-empty block
for (x = 0; x < x_block_count; x++ )
{
for (y = 0; y < y_block_count; y++ )
{
for (z = 0; z < z_block_count; z++ )
{
Block *b = getBlock(x,y,z);
if(b != NULL)
{
// first goes block position
fwrite(&x, sizeof(uint32_t), 1, SaveFile);
fwrite(&y, sizeof(uint32_t), 1, SaveFile);
fwrite(&z, sizeof(uint32_t), 1, SaveFile);
// then block data
fwrite(&b->tile_type, sizeof(uint16_t), BLOCK_SIZE*BLOCK_SIZE, SaveFile);
fwrite(&b->designation, sizeof(uint32_t), BLOCK_SIZE*BLOCK_SIZE, SaveFile);
fwrite(&b->occupancy, sizeof(uint32_t), BLOCK_SIZE*BLOCK_SIZE, SaveFile);
}
}
}
}
return true;
}

@ -0,0 +1,196 @@
/*
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 "DFCommon.h"
#include "DfMap.h"
#include "DfMapHeader.h"
#include "ZlibHelper.h"
/*
bool DfMap::loadMatgloss2(FILE * Decompressed)
{
char buffer [256];
uint32_t nummatgloss;
uint32_t temp;
fread(&nummatgloss, sizeof(uint32_t), 1, Decompressed);
///FIXME: buffer overrun possible? probably not. but fix it anyway.
for(uint32_t i = 0; i< nummatgloss;i++)
{
fread(&temp, sizeof(uint32_t), 1, Decompressed); // string length
fread(&buffer, sizeof(char), temp, Decompressed); // string
buffer[temp] = 0;
v_matgloss[Mat_Stone].push_back(buffer);
}
}
bool DfMap::loadBlocks2(FILE * Decompressed,DfMapHeader & h)
{
uint32_t x, y, z;
uint32_t numveins;
t_vein vein;
// for (uint32_t tile_block = 0U; tile_block < h.tile_block_count; ++tile_block)
{
fread(&x, sizeof(uint32_t), 1, Decompressed);
fread(&y, sizeof(uint32_t), 1, Decompressed);
fread(&z, sizeof(uint32_t), 1, Decompressed);
Block * b = allocBlock(x,y,z);
fread(&b->tile_type, sizeof(b->tile_type), 1, Decompressed);
fread(&b->designation, sizeof(b->designation), 1, Decompressed);
fread(&b->occupancy, sizeof(b->occupancy), 1, Decompressed);
fread(&b->RegionOffsets,sizeof(b->RegionOffsets),1,Decompressed);
// load all veins of this block
fread(&numveins, sizeof(uint32_t), 1, Decompressed);
if(v_matgloss[Mat_Stone].size())
{
applyGeoMatgloss(b);
}
for(uint32_t i = 0; i < numveins; i++)
{
fread(&vein,sizeof(t_vein),1,Decompressed);
b->veins.push_back(vein);
}
if(numveins)
b->collapseVeins();
}
}
bool DfMap::loadRegion2(FILE * Decompressed)
{
uint32_t temp, temp2;
for(uint32_t i = eNorthWest; i< eBiomeCount;i++)
{
fread(&temp, sizeof(uint32_t), 1, Decompressed); // layer vector length
for(uint32_t j = 0; j < temp;j++) // load all geolayers into vectors (just 16bit matgloss indices)
{
fread(&temp2, sizeof(uint16_t), 1, Decompressed);
v_geology[i].push_back(temp2);
}
}
}
bool DfMap::loadVersion2(FILE * Decompressed,DfMapHeader & h)
{
return false;
uint32_t tile_block_count; // how many tile blocks to read from the data location
//uint32_t x_block_count, y_block_count, z_block_count; // DF's map block count
fread(&tile_block_count, sizeof(uint32_t), 1, Decompressed);
fread(&x_block_count, sizeof(uint32_t), 1, Decompressed);
fread(&y_block_count, sizeof(uint32_t), 1, Decompressed);
fread(&z_block_count, sizeof(uint32_t), 1, Decompressed);
// load new size information
//x_block_count = h.x_block_count;
//y_block_count = h.y_block_count;
//z_block_count = h.z_block_count;
// make sure those size variables are in sync
updateCellCount();
// alloc new space for our new size
allocBlockArray(x_block_count,y_block_count,z_block_count);
// fseek(Decompressed, h.map_data_location, SEEK_SET);
// read matgloss vector
loadMatgloss2(Decompressed);
// read region data
loadRegion2(Decompressed);
// read blocks
loadBlocks2(Decompressed,h);
return true;
}
void DfMap::writeMatgloss2(FILE * SaveFile)
{
uint32_t nummatgloss = v_matgloss[Mat_Stone].size();
fwrite(&nummatgloss, sizeof(uint32_t), 1, SaveFile);
for(uint32_t i = 0; i< nummatgloss;i++)
{
const char *saveme = v_matgloss[Mat_Stone][i].c_str();
uint32_t length = v_matgloss[Mat_Stone][i].size();
fwrite(&length, sizeof(uint32_t),1,SaveFile);
fwrite(saveme, sizeof(char), length, SaveFile);
}
}
void DfMap::writeRegion2(FILE * SaveFile)
{
uint32_t temp, temp2;
for(uint32_t i = eNorthWest; i< eBiomeCount;i++)
{
temp = v_geology[i].size();
fwrite(&temp, sizeof(uint32_t), 1, SaveFile); // layer vector length
for(uint32_t j = 0; j < temp;j++) // write all geolayers (just 16bit matgloss indices)
{
temp2 = v_geology[i][j];
fwrite(&temp2, sizeof(uint16_t), 1, SaveFile);
}
}
}
void DfMap::writeBlocks2(FILE * SaveFile)
{
uint32_t x, y, z, numveins;
for (x = 0; x < x_block_count; x++ )
{
for (y = 0; y < y_block_count; y++ )
{
for (z = 0; z < z_block_count; z++ )
{
Block *b = getBlock(x,y,z);
if(b != NULL)
{
// which block it is
fwrite(&x, sizeof(uint32_t), 1, SaveFile);
fwrite(&y, sizeof(uint32_t), 1, SaveFile);
fwrite(&z, sizeof(uint32_t), 1, SaveFile);
// block data
fwrite(&b->tile_type, sizeof(uint16_t), BLOCK_SIZE*BLOCK_SIZE, SaveFile);
fwrite(&b->designation, sizeof(uint32_t), BLOCK_SIZE*BLOCK_SIZE, SaveFile);
fwrite(&b->occupancy, sizeof(uint32_t), BLOCK_SIZE*BLOCK_SIZE, SaveFile);
fwrite(&b->RegionOffsets, sizeof(b->RegionOffsets), 1, SaveFile);
// write all veins
numveins = b->veins.size();
fwrite(&numveins, sizeof(uint32_t), 1, SaveFile);
for(uint32_t i = 0; i < numveins; i++)
{
fwrite(&b->veins[i],sizeof(t_vein),1,SaveFile);
}
}
}
}
}
}
bool DfMap::writeVersion2(FILE * SaveFile)
{
// write matgloss vector
writeMatgloss2(SaveFile);
// write region data
writeRegion2(SaveFile);
// write blocks
writeBlocks2(SaveFile);
return true;
}
*/

@ -0,0 +1,160 @@
// SOURCE: http://www.zlib.net/zpipe.c
#ifndef ZLIB_HELPER_HEADER
#define ZLIB_HELPER_HEADER
#include <zlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
//#define CHUNK 16384
#define CHUNK 262144
/* Compress from file source to file dest until EOF on source.
def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_STREAM_ERROR if an invalid compression
level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
version of the library linked do not match, or Z_ERRNO if there is
an error reading or writing the files. */
inline int def(FILE *source, FILE *dest, int level)
{
int ret, flush;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
/* allocate deflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit(&strm, level);
if (ret != Z_OK)
return ret;
/* compress until end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
strm.next_in = in;
/* run deflate() on input until output buffer not full, finish
compression if all of source has been read in */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, flush); /* no bad return value */
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
assert(strm.avail_in == 0); /* all input will be used */
/* done when last data in file processed */
} while (flush != Z_FINISH);
assert(ret == Z_STREAM_END); /* stream will be complete */
/* clean up and return */
(void)deflateEnd(&strm);
return Z_OK;
}
/* Decompress from file source to file dest until stream ends or EOF.
inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_DATA_ERROR if the deflate data is
invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
the version of the library linked do not match, or Z_ERRNO if there
is an error reading or writing the files. */
inline int inf(FILE *source, FILE *dest)
{
int ret;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
if (strm.avail_in == 0)
break;
strm.next_in = in;
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END);
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
/* report a zlib or i/o error */
inline void zerr(int ret)
{
printf("zpipe: %d\n", ret);
switch (ret) {
case Z_ERRNO:
if (ferror(stdin))
fprintf(stderr,"error reading stdin\n");
if (ferror(stdout))
fprintf(stderr,"error writing stdout\n");
break;
case Z_STREAM_ERROR:
printf("invalid compression level\n");
break;
case Z_DATA_ERROR:
printf("invalid or incomplete deflate data\n");
break;
case Z_MEM_ERROR:
printf("out of memory\n");
break;
case Z_VERSION_ERROR:
printf("zlib version mismatch!\n");
}
}
#endif // ZLIB_HELPER_HEADER

@ -0,0 +1,332 @@
/*
* This is the C++ implementation of the MD5 Message-Digest
* Algorithm desrcipted in RFC 1321.
* I translated the C code from this RFC to C++.
* There is now warranty.
*
* Feb. 12. 2005
* Benjamin Grüdelbach
*/
/*
* Changed unsigned long int types into uint32_t to make this work on 64bit systems.
* Sep. 5. 2009
* Petr Mrázek
*/
/*
* 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.
*/
//md5 class include
#include "md5.h"
// Constants for MD5Transform routine.
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions. */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits. */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/*
FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (unsigned long int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (unsigned long int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (unsigned long int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (unsigned long int)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context. */
void MD5::MD5Init (MD5_CTX *context)
{
context->count[0] = context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/*
MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5::MD5Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen)
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ( (context->count[0] += ((unsigned long int)inputLen << 3))
< ((unsigned long int)inputLen << 3))
context->count[1]++;
context->count[1] += ((unsigned long int)inputLen >> 29);
partLen = 64 - index;
/*
* Transform as many times as possible.
*/
if (inputLen >= partLen)
{
MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD5_memcpy ((POINTER)&context->buffer[index],
(POINTER)&input[i],
inputLen-i);
}
/*
* MD5 finalization. Ends an MD5 message-digest operation, writing the
* the message digest and zeroizing the context.
*/
void MD5::MD5Final (unsigned char digest[16], MD5_CTX *context)
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/*
* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/*
* Zeroize sensitive information.
*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
}
/*
* MD5 basic transformation. Transforms state based on block.
*/
void MD5::MD5Transform (uint32_t state[4], unsigned char block[64])
{
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/*
* Zeroize sensitive information.
*/
MD5_memset ((POINTER)x, 0, sizeof (x));
}
/*
* Encodes input (unsigned long int) into output (unsigned char). Assumes len is
* a multiple of 4.
*/
void MD5::Encode (unsigned char *output, uint32_t *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/*
* Decodes input (unsigned char) into output (unsigned long int). Assumes len is
* a multiple of 4.
*/
void MD5::Decode (uint32_t *output, unsigned char *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((uint32_t)input[j]) |
(((uint32_t)input[j+1]) << 8) |
(((uint32_t)input[j+2]) << 16) |
(((uint32_t)input[j+3]) << 24);
}
/*
* Note: Replace "for loop" with standard memcpy if possible.
*/
void MD5::MD5_memcpy (POINTER output, POINTER input, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
/*
* Note: Replace "for loop" with standard memset if possible.
*/
void MD5::MD5_memset (POINTER output,int value,unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}
/*
* EOF
*/

@ -0,0 +1,92 @@
/*
* This is the C++ implementation of the MD5 Message-Digest
* Algorithm desrcipted in RFC 1321.
* I translated the C code from this RFC to C++.
* There is now warranty.
*
* Feb. 12. 2005
* Benjamin Grüdelbach
*/
/*
* Changed unsigned long int types into uint32_t to make this work on 64bit systems.
* Sep. 5. 2009
* Petr Mrázek
*/
/*
* 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.
*/
//----------------------------------------------------------------------
//include protection
#ifndef MD5_H
#define MD5_H
//----------------------------------------------------------------------
//STL includes
#include <string>
#include <stdint.h>
//----------------------------------------------------------------------
//typedefs
typedef unsigned char *POINTER;
/*
* MD5 context.
*/
typedef struct
{
uint32_t state[4]; /* state (ABCD) */
uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
/*
* MD5 class
*/
class MD5
{
private:
void MD5Transform (uint32_t state[4], unsigned char block[64]);
void Encode (unsigned char*, uint32_t*, unsigned int);
void Decode (uint32_t*, unsigned char*, unsigned int);
void MD5_memcpy (POINTER, POINTER, unsigned int);
void MD5_memset (POINTER, int, unsigned int);
public:
void MD5Init (MD5_CTX*);
void MD5Update (MD5_CTX*, unsigned char*, unsigned int);
void MD5Final (unsigned char [16], MD5_CTX*);
MD5(){};
};
//----------------------------------------------------------------------
//End of include protection
#endif
/*
* EOF
*/

@ -0,0 +1,140 @@
/*
* This is part of 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
*/
/*
* Changed unsigned long int types into uint32_t to make this work on 64bit systems.
* Sep. 5. 2009
* Petr Mrázek
*/
//----------------------------------------------------------------------
//basic includes
#include <fstream>
#include <iostream>
//my includes
#include "md5wrapper.h"
#include "md5.h"
//---------privates--------------------------
/*
* internal hash function, calling
* the basic methods from md5.h
*/
std::string md5wrapper::hashit(std::string text)
{
MD5_CTX ctx;
//init md5
md5->MD5Init(&ctx);
//update with our string
md5->MD5Update(&ctx,
(unsigned char*)text.c_str(),
text.length());
//create the hash
unsigned char buff[16] = "";
md5->MD5Final((unsigned char*)buff,&ctx);
//converte the hash to a string and return it
return convToString(buff);
}
/*
* converts the numeric hash to
* a valid std::string.
* (based on Jim Howard's code;
* http://www.codeproject.com/cpp/cmd5.asp)
*/
std::string md5wrapper::convToString(unsigned char *bytes)
{
char asciihash[33];
int p = 0;
for(int i=0; i<16; i++)
{
::sprintf(&asciihash[p],"%02x",bytes[i]);
p += 2;
}
asciihash[32] = '\0';
return std::string(asciihash);
}
//---------publics--------------------------
//constructor
md5wrapper::md5wrapper()
{
md5 = new MD5();
}
//destructor
md5wrapper::~md5wrapper()
{
delete md5;
}
/*
* creates a MD5 hash from
* "text" and returns it as
* string
*/
std::string md5wrapper::getHashFromString(std::string text)
{
return this->hashit(text);
}
/*
* creates a MD5 hash from
* a file specified in "filename" and
* returns it as string
* (based on Ronald L. Rivest's code
* from RFC1321 "The MD5 Message-Digest Algorithm")
*/
std::string md5wrapper::getHashFromFile(std::string filename)
{
FILE *file;
MD5_CTX context;
int len;
unsigned char buffer[1024], digest[16];
//open file
if ((file = fopen (filename.c_str(), "rb")) == NULL)
{
return "-1";
}
//init md5
md5->MD5Init (&context);
//read the filecontent
while ( (len = fread (buffer, 1, 1024, file)) )
{
md5->MD5Update (&context, buffer, len);
}
/*
generate hash, close the file and return the
hash as std::string
*/
md5->MD5Final (digest, &context);
fclose (file);
return convToString(digest);
}
/*
* EOF
*/

@ -0,0 +1,73 @@
/*
* 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
*/
/*
* Changed unsigned long int types into uint32_t to make this work on 64bit systems.
* Sep. 5. 2009
* Petr Mrázek
*/
//include protection
#ifndef MD5WRAPPER_H
#define MD5WRAPPER_H
//basic includes
#include <string>
//forwards
class MD5;
class md5wrapper
{
private:
MD5 *md5;
/*
* internal hash function, calling
* the basic methods from md5.h
*/
std::string hashit(std::string text);
/*
* converts the numeric giets to
* a valid std::string
*/
std::string convToString(unsigned char *bytes);
public:
//constructor
md5wrapper();
//destructor
~md5wrapper();
/*
* creates a MD5 hash from
* "text" and returns it as
* string
*/
std::string getHashFromString(std::string text);
/*
* creates a MD5 hash from
* a file specified in "filename" and
* returns it as string
*/
std::string getHashFromFile(std::string filename);
};
//include protection
#endif
/*
* EOF
*/

@ -0,0 +1,116 @@
/*
www.sourceforge.net/projects/tinyxml
Original file by Yves Berquin.
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.
*/
/*
* THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005.
*/
#ifndef TIXML_USE_STL
#include "tinystr.h"
// Error value for find primitive
const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);
// Null rep.
TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } };
void TiXmlString::reserve (size_type cap)
{
if (cap > capacity())
{
TiXmlString tmp;
tmp.init(length(), cap);
memcpy(tmp.start(), data(), length());
swap(tmp);
}
}
TiXmlString& TiXmlString::assign(const char* str, size_type len)
{
size_type cap = capacity();
if (len > cap || cap > 3*(len + 8))
{
TiXmlString tmp;
tmp.init(len);
memcpy(tmp.start(), str, len);
swap(tmp);
}
else
{
memmove(start(), str, len);
set_size(len);
}
return *this;
}
TiXmlString& TiXmlString::append(const char* str, size_type len)
{
size_type newsize = length() + len;
if (newsize > capacity())
{
reserve (newsize + capacity());
}
memmove(finish(), str, len);
set_size(newsize);
return *this;
}
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
{
TiXmlString tmp;
tmp.reserve(a.length() + b.length());
tmp += a;
tmp += b;
return tmp;
}
TiXmlString operator + (const TiXmlString & a, const char* b)
{
TiXmlString tmp;
TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
tmp.reserve(a.length() + b_len);
tmp += a;
tmp.append(b, b_len);
return tmp;
}
TiXmlString operator + (const char* a, const TiXmlString & b)
{
TiXmlString tmp;
TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
tmp.reserve(a_len + b.length());
tmp.append(a, a_len);
tmp += b;
return tmp;
}
#endif // TIXML_USE_STL

@ -0,0 +1,319 @@
/*
www.sourceforge.net/projects/tinyxml
Original file by Yves Berquin.
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.
*/
/*
* THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005.
*
* - completely rewritten. compact, clean, and fast implementation.
* - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems)
* - fixed reserve() to work as per specification.
* - fixed buggy compares operator==(), operator<(), and operator>()
* - fixed operator+=() to take a const ref argument, following spec.
* - added "copy" constructor with length, and most compare operators.
* - added swap(), clear(), size(), capacity(), operator+().
*/
#ifndef TIXML_USE_STL
#ifndef TIXML_STRING_INCLUDED
#define TIXML_STRING_INCLUDED
#include <assert.h>
#include <string.h>
/* The support for explicit isn't that universal, and it isn't really
required - it is used to check that the TiXmlString class isn't incorrectly
used. Be nice to old compilers and macro it here:
*/
#if defined(_MSC_VER) && (_MSC_VER >= 1200 )
// Microsoft visual studio, version 6 and higher.
#define TIXML_EXPLICIT explicit
#elif defined(__GNUC__) && (__GNUC__ >= 3 )
// GCC version 3 and higher.s
#define TIXML_EXPLICIT explicit
#else
#define TIXML_EXPLICIT
#endif
/*
TiXmlString is an emulation of a subset of the std::string template.
Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
Only the member functions relevant to the TinyXML project have been implemented.
The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
a string and there's no more room, we allocate a buffer twice as big as we need.
*/
class TiXmlString
{
public :
// The size type used
typedef size_t size_type;
// Error value for find primitive
static const size_type npos; // = -1;
// TiXmlString empty constructor
TiXmlString () : rep_(&nullrep_)
{
}
// TiXmlString copy constructor
TiXmlString ( const TiXmlString & copy) : rep_(0)
{
init(copy.length());
memcpy(start(), copy.data(), length());
}
// TiXmlString constructor, based on a string
TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0)
{
init( static_cast<size_type>( strlen(copy) ));
memcpy(start(), copy, length());
}
// TiXmlString constructor, based on a string
TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0)
{
init(len);
memcpy(start(), str, len);
}
// TiXmlString destructor
~TiXmlString ()
{
quit();
}
// = operator
TiXmlString& operator = (const char * copy)
{
return assign( copy, (size_type)strlen(copy));
}
// = operator
TiXmlString& operator = (const TiXmlString & copy)
{
return assign(copy.start(), copy.length());
}
// += operator. Maps to append
TiXmlString& operator += (const char * suffix)
{
return append(suffix, static_cast<size_type>( strlen(suffix) ));
}
// += operator. Maps to append
TiXmlString& operator += (char single)
{
return append(&single, 1);
}
// += operator. Maps to append
TiXmlString& operator += (const TiXmlString & suffix)
{
return append(suffix.data(), suffix.length());
}
// Convert a TiXmlString into a null-terminated char *
const char * c_str () const { return rep_->str; }
// Convert a TiXmlString into a char * (need not be null terminated).
const char * data () const { return rep_->str; }
// Return the length of a TiXmlString
size_type length () const { return rep_->size; }
// Alias for length()
size_type size () const { return rep_->size; }
// Checks if a TiXmlString is empty
bool empty () const { return rep_->size == 0; }
// Return capacity of string
size_type capacity () const { return rep_->capacity; }
// single char extraction
const char& at (size_type index) const
{
assert( index < length() );
return rep_->str[ index ];
}
// [] operator
char& operator [] (size_type index) const
{
assert( index < length() );
return rep_->str[ index ];
}
// find a char in a string. Return TiXmlString::npos if not found
size_type find (char lookup) const
{
return find(lookup, 0);
}
// find a char in a string from an offset. Return TiXmlString::npos if not found
size_type find (char tofind, size_type offset) const
{
if (offset >= length()) return npos;
for (const char* p = c_str() + offset; *p != '\0'; ++p)
{
if (*p == tofind) return static_cast< size_type >( p - c_str() );
}
return npos;
}
void clear ()
{
//Lee:
//The original was just too strange, though correct:
// TiXmlString().swap(*this);
//Instead use the quit & re-init:
quit();
init(0,0);
}
/* Function to reserve a big amount of data when we know we'll need it. Be aware that this
function DOES NOT clear the content of the TiXmlString if any exists.
*/
void reserve (size_type cap);
TiXmlString& assign (const char* str, size_type len);
TiXmlString& append (const char* str, size_type len);
void swap (TiXmlString& other)
{
Rep* r = rep_;
rep_ = other.rep_;
other.rep_ = r;
}
private:
void init(size_type sz) { init(sz, sz); }
void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; }
char* start() const { return rep_->str; }
char* finish() const { return rep_->str + rep_->size; }
struct Rep
{
size_type size, capacity;
char str[1];
};
void init(size_type sz, size_type cap)
{
if (cap)
{
// Lee: the original form:
// rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));
// doesn't work in some cases of new being overloaded. Switching
// to the normal allocation, although use an 'int' for systems
// that are overly picky about structure alignment.
const size_type bytesNeeded = sizeof(Rep) + cap;
const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int );
rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );
rep_->str[ rep_->size = sz ] = '\0';
rep_->capacity = cap;
}
else
{
rep_ = &nullrep_;
}
}
void quit()
{
if (rep_ != &nullrep_)
{
// The rep_ is really an array of ints. (see the allocator, above).
// Cast it back before delete, so the compiler won't incorrectly call destructors.
delete [] ( reinterpret_cast<int*>( rep_ ) );
}
}
Rep * rep_;
static Rep nullrep_;
} ;
inline bool operator == (const TiXmlString & a, const TiXmlString & b)
{
return ( a.length() == b.length() ) // optimization on some platforms
&& ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare
}
inline bool operator < (const TiXmlString & a, const TiXmlString & b)
{
return strcmp(a.c_str(), b.c_str()) < 0;
}
inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }
inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; }
inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }
inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }
inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }
inline bool operator == (const char* a, const TiXmlString & b) { return b == a; }
inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }
inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b);
TiXmlString operator + (const TiXmlString & a, const char* b);
TiXmlString operator + (const char* a, const TiXmlString & b);
/*
TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
Only the operators that we need for TinyXML have been developped.
*/
class TiXmlOutStream : public TiXmlString
{
public :
// TiXmlOutStream << operator.
TiXmlOutStream & operator << (const TiXmlString & in)
{
*this += in;
return *this;
}
// TiXmlOutStream << operator.
TiXmlOutStream & operator << (const char * in)
{
*this += in;
return *this;
}
} ;
#endif // TIXML_STRING_INCLUDED
#endif // TIXML_USE_STL

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,53 @@
/*
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.
*/
#include "tinyxml.h"
// The goal of the seperate error file is to make the first
// step towards localization. tinyxml (currently) only supports
// english error messages, but the could now be translated.
//
// It also cleans up the code a bit.
//
const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
{
"No error",
"Error",
"Failed to open file",
"Memory allocation failed.",
"Error parsing Element.",
"Failed to read Element name",
"Error reading Element value.",
"Error reading Attributes.",
"Error: empty tag.",
"Error reading end tag.",
"Error parsing Unknown.",
"Error parsing Comment.",
"Error parsing Declaration.",
"Error document empty.",
"Error null (0) or unexpected EOF found in input stream.",
"Error parsing CDATA.",
"Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,553 @@
<?xml version="1.0" ?>
<DFExtractor>
<!-- USE A FIXED WIDTH FONT! -->
<MemoryDescriptors>
_____________________________________________
|\'-._( / |
| \ .'-._\ , ,|
|-.\' .-; .'\`-' |
| \ .' ( _.' \ |
|.--.\' _) ;-; \._|
| ` _\(_)/_ \ `'-,_,-'\ |
jgs____ /(O)\ _________________/____)_`-._\|
| |
| Old unsupported versions |
|------------------------------------------->
<!--<Entry version="v0.27.176.38a" os="windows">
<HexValue name="pe_timestamp">0x47B6FAC2</HexValue>
<Address name="map_data">0x014A4EAC</Address>
<Address name="x_count">0x014A4EC4</Address>
<Address name="y_count">0x014A4EC8</Address>
<Address name="z_count">0x014A4ECC</Address>
<Offset name="type">0x005E</Offset>
<Offset name="designation">0x0260</Offset>
<Offset name="occupancy">0x0660</Offset>
</Entry>
<Entry version="v0.28.181.40c" os="windows">
<HexValue name="pe_timestamp">0x48AD802B</HexValue>
<Address name="map_data">0x015C3D60</Address>
<Address name="x_count">0x015C3D78</Address>
<Address name="y_count">0x015C3D7C</Address>
<Address name="z_count">0x015C3D80</Address>
<Offset name="type">0x0062</Offset>
<Offset name="designation">0x0264</Offset>
<Offset name="occupancy">0x0664</Offset>
</Entry>-->
.,:rsr,
:2;,;r2A@@5
@2::s5A#@@@ @r. .
sd;:riXA#@@ :@@@Gir;;AS9
Bs::sS3A#@2 @@#AhXirsS#;
iHrLr5d#@@@ .@#95sr;;rie
i*' `*@3 @@A2sr;:;r#5
:..:rll: @@A5sr::r3@
@Hr;iZ#@@@@ `:rr;;;;:
S@r.;i2#@@@ @s. ..
@2::ri2A@@# B@G2ir:...5i
:@r,r3X##@@ @G5sr:..,:A
.@Ar;;rSB@@# H#2sr;,..,is
.' `* ,@ASs;:..,:B
;rr;:,..,:.
`'''
W I N D O W S
and
W I N E
<Entry version="v0.28.181.40d" os="windows" id="40dwin">
<!-- identification -->
<HexValue name="pe_timestamp">0x48C330DF</HexValue>
<String name="md5">2c686c26307dcccd7c36cc79737ebe4f</String>
<!-- map data -->
<Address name="map_data">0x015C4D58</Address>
<Address name="constructions">0x0156F8B0</Address>
<Address name="buildings">0x015838a0</Address>
<Address name="vegetation">0x01587A24</Address>
<!-- size of the map -->
<Address name="x_count">0x015C4D70</Address>
<Address name="y_count">0x015C4D74</Address>
<Address name="z_count">0x015C4D78</Address>
<!-- position of the map in world coords -->
<Address name="region_x">0x015C4D88</Address>
<Address name="region_y">0x015C4D8C</Address>
<Address name="region_z">0x015C4D90</Address>
<!-- map block offsets -->
<Offset name="v_vein">0x08</Offset>
<HexValue name="v_vein_size">0x2C</HexValue>
<Offset name="type">0x0062</Offset>
<Offset name="designation">0x0264</Offset>
<Offset name="occupancy">0x0664</Offset>
<Offset name="biome_stuffs">0x1D64</Offset>
<!-- tree and shrub offsets -->
<Offset name="tree_desc_offset">0x70</Offset>
<!-- the world and its offsets -->
<Address name="world">0x015C6388</Address>
<Offset name="world_size_x">0x84</Offset>
<Offset name="world_size_y">0x86</Offset>
<Offset name="w_geoblocks">0x684</Offset>
<Offset name="w_regions_arr">0x6B4</Offset>
<!-- values for the region structure -->
<HexValue name="region_size">0x5C</HexValue>
<Offset name="region_geo_index_off">0x58</Offset>
<!-- geoblock offset(s?) -->
<Offset name="geolayer_geoblock_offset">0x4</Offset>
<!-- matgloss vectors -->
<Address name="matgloss">0x015C6D70</Address>
<HexValue name="matgloss_skip">0x10</HexValue>
<!-- only stone and metal have color loaded... -->
<Offset name="matgloss_stone_color">0x84</Offset>
<Offset name="matgloss_metal_color">0x60</Offset>
<VTable>
<class vtable="0x00979fe4" name="stockpile" />
<class vtable="0x00979d34" name="zone" />
<class vtable="0x0097e7ec" name="construction_blueprint" />
<!-- BUILDINGS -->
<class vtable="0x0097e3cc" name="wagon"/>
<class vtable="0x0097b3ac" name="armor_stand"/>
<class vtable="0x0097d1ec" name="bed"/>
<class vtable="0x0097d4ac" name="seat"/>
<class vtable="0x0097d76c" name="burial_receptacle"/>
<class vtable="0x0097b50c" name="door"/>
<class vtable="0x0097b92c" name="floodgate"/>
<class vtable="0x0097b66c" name="floor_hatch"/>
<class vtable="0x0097ba8c" name="wall_grate"/>
<class vtable="0x0097bbec" name="floor_grate"/>
<class vtable="0x0097bd4c" name="vertical_bars"/>
<class vtable="0x0097beac" name="floor_bars"/>
<class vtable="0x0097b0ec" name="cabinet"/>
<class vtable="0x0097af8c" name="container"/>
<multiclass vtable="0x0097e10c" name="workshop" typeoffset="0xC8">
<class name="alchemists_laboratory" type="0x0"/>
<class name="carpenters_workshop" type="0x1"/>
<class name="farmers_workshop" type="0x2"/>
<class name="masons_workshop" type="0x3"/>
<class name="craftdwarfs_workshop" type="0x4"/>
<class name="jewelers_workshop" type="0x5"/>
<class name="metalsmiths_workshop" type="0x6"/>
<class name="magma_forge" type="0x7"/>
<class name="bowyers_workshop" type="0x8"/>
<class name="mechanics_workshop" type="0x9"/>
<class name="siege_workshop" type="0xA"/>
<class name="butchers_shop" type="0xB"/>
<class name="leather_works" type="0xC"/>
<class name="tanners_shop" type="0xD"/>
<class name="clothiers_shop" type="0xE"/>
<class name="fishery" type="0xF"/>
<class name="still" type="0x10"/>
<class name="loom" type="0x11"/>
<class name="quern" type="0x12"/>
<class name="kennels" type="0x13"/>
<class name="kitchen" type="0x14"/>
<class name="ashery" type="0x15"/>
<class name="dyers_shop" type="0x16"/>
<class name="millstone" type="0x17"/>
</multiclass>
<class vtable="0x0097dcec" name="farm_plot"/>
<class vtable="0x0097b24c" name="weapon_rack"/>
<class vtable="0x0097d8cc" name="statue"/>
<class vtable="0x0097d34c" name="table"/>
<class vtable="0x0097e68c" name="paved_road"/>
<class vtable="0x0097b7cc" name="bridge"/>
<class vtable="0x00979e84" name="well"/>
<multiclass vtable="0x0097d08c" name="siege engine" typeoffset="0xC8">
<class name="catapult" type="0x0"/>
<class name="ballista" type="0x1"/>
</multiclass>
<multiclass vtable="0x0097dfac" name="furnace" typeoffset="0xDA">
<class name="wood_furnace" type="0x0"/>
<class name="smelter" type="0x1"/>
<class name="glass_furnace" type="0x2"/>
<class name="kiln" type="0x3"/>
<class name="magma_smelter" type="0x4"/>
<class name="magma_glass_furnace" type="0x5"/>
<class name="magma_kiln" type="0x6"/>
</multiclass>
<class vtable="0x0097db8c" name="glass_window"/>
<class vtable="0x0097da2c" name="gem_window"/>
<class vtable="0x0097e26c" name="trade_depot"/>
<multiclass vtable="0x0097c00c" name="mechanism" typeoffset="0xC8">
<class name="lever" type="0x0"/>
<class name="pressure_plate" type="0x1"/>
<class name="cage_trap" type="0x2"/>
<class name="stonefall_trap" type="0x3"/>
<class name="weapon_trap" type="0x4"/>
</multiclass>
<class vtable="0x0097c6ec" name="spike" />
<class vtable="0x0097de4c" name="animal_trap" />
<class vtable="0x0097c9ac" name="screw_pump"/>
<class vtable="0x0097cb0c" name="water_wheel"/>
<class vtable="0x0097cc6c" name="windmill"/>
<class vtable="0x0097c16c" name="gear_assembly"/>
<class vtable="0x0097c2cc" name="horizontal_axle"/>
<class vtable="0x0097c42c" name="vertical_axle"/>
<class vtable="0x0097c58c" name="support"/>
<class vtable="0x0097cf2c" name="cage"/>
<class vtable="0x0097c84c" name="archery_target"/>
<class vtable="0x0097cdcc" name="restraint"/>
</VTable>
</Entry>
<!-- Windows 40d## sub-versions, should inherit only vtable from 40d -->
<Entry version="v0.28.181.40d9" os="windows" id="40d9win" base="40dwin">
<!-- identification -->
<HexValue name="pe_timestamp">0x4967C2E0</HexValue>
<String name="md5">aea5a207b8b1cda942502f97a429f6c3</String>
<!-- map data -->
<Address name="map_data">0x01531EC0</Address>
<Address name="constructions">0x014da5e0</Address>
<Address name="buildings">0x014ee978</Address>
<Address name="vegetation">0x014F4B4C</Address>
<!-- tree and shrub offsets -->
<Offset name="tree_desc_offset">0x70</Offset>
<!-- size of the map -->
<Address name="x_count">0x01531EE0</Address>
<Address name="y_count">0x01531EE4</Address>
<Address name="z_count">0x01531EE8</Address>
<!-- position of the map in world coords -->
<Address name="region_x">0x01531EF8</Address>
<Address name="region_y">0x01531EFC</Address>
<Address name="region_z">0x01531F00</Address>
<!-- map block offsets -->
<Offset name="v_vein">0x10</Offset>
<HexValue name="v_vein_size">0x2C</HexValue>
<Offset name="type">0x0082</Offset>
<Offset name="designation">0x0284</Offset>
<Offset name="occupancy">0x0684</Offset>
<Offset name="biome_stuffs">0x1D84</Offset>
<!-- the world and its offsets -->
<Address name="world">0x015334F8</Address>
<Offset name="world_size_x">0x84</Offset>
<Offset name="world_size_y">0x86</Offset>
<Offset name="w_geoblocks">0x75C</Offset>
<Offset name="w_regions_arr">0x79C</Offset>
<!-- values for the region structure -->
<HexValue name="region_size">0x64</HexValue>
<Offset name="region_geo_index_off">0x60</Offset>
<!-- geoblock offset(s?) -->
<Offset name="geolayer_geoblock_offset">0xC</Offset>
<!-- matgloss vectors -->
<Address name="matgloss">0x01534030</Address>
<HexValue name="matgloss_skip">0x18</HexValue>
<!-- door: 0x8ea1e4 -->
<VTable rebase="-0x91328">
<!-- Isn't it just /lovely/ how simple things become?
When you specify only typeoffset, nothing else is touched. Same for vtable. -->
<multiclass name="workshop" typeoffset="0x100" />
<multiclass name="siege engine" typeoffset="0x100" />
<multiclass name="furnace" typeoffset="0x11A" />
<multiclass name="mechanism" typeoffset="0x100" />
</VTable>
</Entry>
<Entry version="v0.28.181.40d11" os="windows" rebase="0x2d388" id="40d11win" base="40d9win">
<!-- identification -->
<HexValue name="pe_timestamp">0x49C82D3F</HexValue>
<String name="md5">6f81231b845e9c9dc29aaf57705ccc7c</String>
<!-- door: 0x8e91e4 -->
<VTable rebase="-0x1000" />
</Entry>
<Entry version="v0.28.181.40d12" os="windows" id="40d12win" base="40d11win">
<!-- identification -->
<HexValue name="pe_timestamp">0x4A3CCB7F</HexValue>
<String name="md5">6ea1de36af8e1666bd6478736e298c4c</String>
<!-- map data -->
<Address name="map_data">0x015FACCC</Address>
<Address name="constructions">0x015A33B8</Address>
<Address name="buildings">0x015B7750</Address>
<Address name="vegetation">0x015BD924</Address>
<!-- size of the map -->
<Address name="x_count">0x015FACEC</Address>
<Address name="y_count">0x015FACF0</Address>
<Address name="z_count">0x015FACF4</Address>
<!-- position of the map in world coords -->
<Address name="region_x">0x015FAD04</Address>
<Address name="region_y">0x015FAD08</Address>
<Address name="region_z">0x015FAD0C</Address>
<!-- the world and its offsets -->
<Address name="world">0x015FC304</Address>
<!-- matgloss vectors -->
<Address name="matgloss">0x015FCE3C</Address>
<!-- door: 0x8db5e4 -->
<VTable rebase="-0xDC00" />
</Entry>
<Entry version="v0.28.181.40d13" os="windows" id="40d13win" base="40d12win" rebase="0x5090">
<!-- identification -->
<HexValue name="pe_timestamp">0x4A51C26E</HexValue>
<String name="md5">04a8d8ce311d8ac75e4241bef68d3147</String>
<!-- map_data = 0x015FFD5C -->
<!-- door: 0x8df5ec -->
<VTable rebase="0x4008" />
</Entry>
<Entry version="v0.28.181.40d14" os="windows" id="40d14win" base="40d13win" rebase="0x2010">
<!-- identification -->
<HexValue name="pe_timestamp">0x4A8623D2</HexValue>
<String name="md5">781a2e51be4056a7320108f8f0df8a13</String>
<!-- map_data = 0x01601D6C -->
<!-- door: 0x8e15dc -->
<VTable rebase="0x1FF0" />
</Entry>
<Entry version="v0.28.181.40d15" os="windows" id="40d15win" base="40d14win" rebase="0x18">
<!-- identification -->
<HexValue name="pe_timestamp">0x4A9A6090</HexValue>
<String name="md5">12cc4a3dbb6e6dfd7bc7aee458b9471a</String>
<!-- map_data = 0x01601D84 -->
<!-- door: 0x8e15d4 -->
<VTable rebase="-0x8" />
</Entry>
<Entry version="v0.28.181.40d16" os="windows" base="40d15win">
<!-- identification -->
<HexValue name="pe_timestamp">0x4A9B1A72</HexValue>
<String name="md5">59ab29021aca9f3c66b1ab102fb3ceea</String>
<!-- map_data = 0x01601D84 -->
<!-- door: 0x8e15d4, no VTable rebase needed -->
</Entry>
.-"""-.
' \
|,. ,-. |
|()L( ()| |
|,' `".| |
|.___.',| `
.j `--"' ` `.
/ ' ' \
/ / ` `.
/ / ` .
/ / l |
. , L I N U X | |
,"`. .| |
_.' ``. | `..-'l
| `.`, | `.
| `. __.j )
|__ |--""___| ,-'
`"--...,+"""" `._,.-'
<Entry version="v0.28.181.40d9" os="linux" id="40d9lin">
<!-- identification -->
<String name="md5">992afd73855e787860277f53d18afcbb</String>
<!-- map data -->
<Address name="map_data">0x09372FC0</Address>
<Address name="constructions">0x0931ED38</Address>
<!-- srsly, WTF? -->
<!--<Address name="buildings">0x09332B54</Address>-->
<Address name="buildings">0x09332B60</Address>
<!--<Address name="buildings">0x09332B90</Address>-->
<!--<Address name="buildings">0x09332C80</Address>-->
<!--<Address name="buildings">0x09332EF0</Address>-->
<Address name="vegetation">0x09335CB0</Address>
<!-- tree and shrub offsets -->
<Offset name="tree_desc_offset">0x40</Offset>
<!-- size of the map -->
<Address name="x_count">0x09372FD4</Address>
<Address name="y_count">0x09372FD8</Address>
<Address name="z_count">0x09372FDC</Address>
<!-- position of the map in world coords -->
<Address name="region_x">0x09372FEC</Address>
<Address name="region_y">0x09372FF0</Address>
<Address name="region_z">0x09372FF4</Address>
<!-- map block offsets -->
<Offset name="v_vein">0x08</Offset>
<HexValue name="v_vein_size">0x2C</HexValue>
<Offset name="type">0x0052</Offset>
<Offset name="designation">0x0254</Offset>
<Offset name="occupancy">0x0654</Offset>
<Offset name="biome_stuffs">0x1D54</Offset>
<!-- the world and its offsets -->
<Address name="world">0x093745EC</Address>
<Offset name="world_size_x">0x54</Offset>
<Offset name="world_size_y">0x56</Offset>
<Offset name="w_geoblocks">0x5A4</Offset>
<Offset name="w_regions_arr">0x5C8</Offset>
<!-- values for the region structure -->
<HexValue name="region_size">0x58</HexValue>
<Offset name="region_geo_index_off">0x54</Offset>
<!-- geoblock offset(s?) -->
<Offset name="geolayer_geoblock_offset">0x4</Offset>
<!-- matgloss vectors -->
<Address name="matgloss">0x9374E88</Address>
<HexValue name="matgloss_skip">0xC</HexValue>
<VTable>
<class vtable="0x087981a8" name="stockpile" />
<class vtable="0x08799e08" name="zone" />
<class vtable="0x08797448" name="construction_blueprint" />
<!-- BUILDINGS -->
<class vtable="0x0879a0e8" name="wagon"/>
<class vtable="0x08798a88" name="armor_stand"/>
<class vtable="0x08798908" name="bed"/>
<class vtable="0x08799088" name="seat"/>
<class vtable="0x08798028" name="burial_receptacle"/>
<class vtable="0x0879a868" name="door"/>
<class vtable="0x0879b168" name="floodgate"/>
<class vtable="0x0879a6e8" name="floor_hatch"/>
<class vtable="0x0879ae68" name="wall_grate"/>
<class vtable="0x0879afe8" name="floor_grate"/>
<class vtable="0x0879ace8" name="vertical_bars"/>
<class vtable="0x0879ab68" name="floor_bars"/>
<class vtable="0x0879a568" name="cabinet"/>
<class vtable="0x0879a3e8" name="container"/>
<multiclass vtable="0x08799688" name="workshop" typeoffset="0xAC">
<class name="alchemists_laboratory" type="0x0"/>
<class name="carpenters_workshop" type="0x1"/>
<class name="farmers_workshop" type="0x2"/>
<class name="masons_workshop" type="0x3"/>
<class name="craftdwarfs_workshop" type="0x4"/>
<class name="jewelers_workshop" type="0x5"/>
<class name="metalsmiths_workshop" type="0x6"/>
<class name="magma_forge" type="0x7"/>
<class name="bowyers_workshop" type="0x8"/>
<class name="mechanics_workshop" type="0x9"/>
<class name="siege_workshop" type="0xA"/>
<class name="butchers_shop" type="0xB"/>
<class name="leather_works" type="0xC"/>
<class name="tanners_shop" type="0xD"/>
<class name="clothiers_shop" type="0xE"/>
<class name="fishery" type="0xF"/>
<class name="still" type="0x10"/>
<class name="loom" type="0x11"/>
<class name="quern" type="0x12"/>
<class name="kennels" type="0x13"/>
<class name="kitchen" type="0x14"/>
<class name="ashery" type="0x15"/>
<class name="dyers_shop" type="0x16"/>
<class name="millstone" type="0x17"/>
</multiclass>
<class vtable="0x08799c88" name="farm_plot"/>
<class vtable="0x08798c08" name="weapon_rack"/>
<class vtable="0x08798488" name="statue"/>
<class vtable="0x08798d88" name="table"/>
<class vtable="0x08797ea8" name="paved_road"/>
<class vtable="0x0879a9e8" name="bridge"/>
<class vtable="0x08798608" name="well"/>
<multiclass vtable="0x8799808" name="siege engine" typeoffset="0xAC">
<class name="catapult" type="0x0"/>
<class name="ballista" type="0x1"/>
</multiclass>
<multiclass vtable="0x08799b08" name="furnace" typeoffset="0xBA">
<class name="wood_furnace" type="0x0"/>
<class name="smelter" type="0x1"/>
<class name="glass_furnace" type="0x2"/>
<class name="kiln" type="0x3"/>
<class name="magma_smelter" type="0x4"/>
<class name="magma_glass_furnace" type="0x5"/>
<class name="magma_kiln" type="0x6"/>
</multiclass>
<class vtable="0x0879bae8" name="glass_window"/>
<class vtable="0x0879b948" name="gem_window"/>
<class vtable="0x08799f68" name="trade_depot"/>
<multiclass vtable="0x08799988" name="mechanism" typeoffset="0xAC">
<class name="lever" type="0x0"/>
<class name="pressure_plate" type="0x1"/>
<class name="cage_trap" type="0x2"/>
<class name="stonefall_trap" type="0x3"/>
<class name="weapon_trap" type="0x4"/>
</multiclass>
<class vtable="0x08799208" name="spike" />
<class vtable="0x08798f08" name="animal_trap" />
<class vtable="0x08796cc8" name="screw_pump"/>
<class vtable="0x08796fc8" name="water_wheel"/>
<class vtable="0x08796e48" name="windmill"/>
<class vtable="0x087978a8" name="gear_assembly"/>
<class vtable="0x08797148" name="horizontal_axle"/>
<class vtable="0x087972c8" name="vertical_axle"/>
<class vtable="0x08799388" name="support"/>
<class vtable="0x08797a28" name="cage"/>
<class vtable="0x08799508" name="archery_target"/>
<class vtable="0x08797ba8" name="restraint"/>
</VTable>
</Entry>
<Entry version="v0.28.181.40d11" os="linux" base="40d9lin" rebase="-0x73820">
<!-- identification -->
<String name="md5">fb8ecac8a12af5d0d7b1707078985d0d</String>
<!--TODO: <Address name="notes">0x092ab244</Address>-->
<VTable rebase="-0x5e360" />
</Entry>
<!-- re-specified addresses here, offsets and hexvals remain same -->
<Entry version="v0.28.181.40d12" os="linux" base="40d9lin" id="40d12lin">
<!-- identification -->
<String name="md5">4367c59934cbcf14f43fd3af6444c455</String>
<!-- map data -->
<Address name="map_data">0x08F95BBC</Address>
<Address name="constructions">0x08F41918</Address>
<Address name="buildings">0x08F55740</Address>
<Address name="vegetation">0x08F58890</Address>
<!-- size of the map -->
<Address name="x_count">0x08F95BD0</Address>
<Address name="y_count">0x08F95BD4</Address>
<Address name="z_count">0x08F95BD8</Address>
<!-- position of the map in world coords -->
<Address name="region_x">0x08F95BE8</Address>
<Address name="region_y">0x08F95BEC</Address>
<Address name="region_z">0x08F95BF0</Address>
<!-- the world and its offsets -->
<Address name="world">0x08F971E8</Address>
<!-- matgloss vectors -->
<Address name="matgloss">0x08F97A84</Address>
<VTable rebase="-0xd6f00" />
<!--<class vtable="0x086C3968" name="door"/>-->
</Entry>
<Entry version="v0.28.181.40d13" os="linux" id="40d13lin" base="40d12lin" rebase="0x5020">
<!-- identification -->
<String name="md5">2f3cb9d720e9fe8844c02c72a2b20bbd</String>
<!-- map_data = 0x8F9ABDC -->
<VTable rebase="0x3A00" />
<!--<class vtable="0x086C7368" name="door"/>-->
</Entry>
<Entry version="v0.28.181.40d14" os="linux" id="40d14lin" base="40d13lin">
<!-- identification -->
<String name="md5">dab3ce6bc074529706a1e5fe1273108c</String>
<!-- map_data = 0x8F9ABDC -->
<VTable rebase="0x300" />
<!--<class vtable="0x086C7668" name="door"/>-->
</Entry>
<Entry version="v0.28.181.40d15" os="linux" id="40d15lin" base="40d14lin">
<!-- identification -->
<String name="md5">4f55a1dcc326786271f221de23c425b5</String>
<!-- map_data = 0x8F9ABDC -->
<VTable rebase="0x260" />
<!--<class vtable="0x086c78c8" name="door"/>-->
</Entry>
<Entry version="v0.28.181.40d16" os="linux" base="40d15lin">
<!-- identification -->
<String name="md5">022b933926e08da49c6df8649295f2b7</String>
<!-- map_data = 0x8F9ABDC -->
<!--<class vtable="0x086c78c8" name="door"/>-->
</Entry>
</MemoryDescriptors>
<!-- Windows logo by M$, spiderweb by jgs -->
</DFExtractor>

@ -0,0 +1,22 @@
# don't use this file directly. use the one in the root folder of the project
# this is required to ensure we use the right configuration for the system.
IF(UNIX)
add_definitions(-DLINUX_BUILD)
ENDIF(UNIX)
# a benchmark program
ADD_EXECUTABLE(expbench expbench.cpp)
TARGET_LINK_LIBRARIES(expbench dfhack)
# a reveal clone
ADD_EXECUTABLE(reveal reveal.cpp)
TARGET_LINK_LIBRARIES(reveal dfhack)
# prospector - produces a list of available materials and their quantities
ADD_EXECUTABLE(prospector prospector.cpp)
TARGET_LINK_LIBRARIES(prospector dfhack)
# cleanmap - removes mud, snow, blood and similar stuff from a map. farmers beware
ADD_EXECUTABLE(cleanmap cleanmap.cpp)
TARGET_LINK_LIBRARIES(cleanmap dfhack)

@ -0,0 +1,50 @@
// Map cleaner. Removes all the snow, mud spills, blood and vomit from map tiles.
#include <iostream>
#include <stdint.h>
#include <vector>
using namespace std;
#include <DFTypes.h>
#include <DFHackAPI.h>
int main (void)
{
uint32_t x_max,y_max,z_max;
uint32_t num_blocks = 0;
uint32_t bytes_read = 0;
t_occupancy occupancies[256];
DFHackAPI DF("Memory.xml");
if(!DF.Attach())
{
cerr << "DF not found" << endl;
return 1;
}
DF.InitMap();
DF.getSize(x_max,y_max,z_max);
// 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(DF.isValidBlock(x,y,z))
{
// read block designations
DF.ReadOccupancy(x,y,z, (uint32_t *) occupancies);
// change the hidden flag to 0
for (uint32_t i = 0; i < 256;i++)
{
occupancies[i].unibits.splatter = 0;
}
// write the designations back
DF.WriteOccupancy(x,y,z, (uint32_t *) occupancies);
}
}
}
}
return 0;
}

@ -0,0 +1,50 @@
// This program exports the entire map from DF. Takes roughly 6.6 seconds for 1000 cycles on my Linux machine. ~px
#include <iostream>
#include <stdint.h>
#include <vector>
using namespace std;
#include <DFTypes.h>
#include <DFHackAPI.h>
int main (void)
{
uint32_t x_max,y_max,z_max;
uint32_t num_blocks = 0;
uint32_t bytes_read = 0;
uint16_t tiletypes[16][16];
t_designation designations[16][16];
t_occupancy occupancies[16][16];
DFHackAPI DF("Memory.xml");
if(!DF.Attach())
{
cerr << "DF not found" << endl;
return 1;
}
DF.InitMap();
DF.getSize(x_max,y_max,z_max);
for(uint32_t i = 0; i< 1000;i++)
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(DF.isValidBlock(x,y,z))
{
DF.ReadTileTypes(x,y,z, (uint16_t *) tiletypes);
DF.ReadDesignations(x,y,z, (uint32_t *) designations);
DF.ReadOccupancy(x,y,z, (uint32_t *) occupancies);
num_blocks ++;
bytes_read += 256 * (4 + 4 + 2);
}
}
}
}
cout << num_blocks << " blocks read" << endl;
cout << bytes_read / (1024 * 1024) << " MB" << endl;
return 0;
}

@ -0,0 +1,168 @@
// produces a list of vein materials available on the map. can be run with '-a' modifier to show even unrevealed minerals deep underground
// with -b modifier, it will show base layer materials too
// TODO: use material colors to make the output prettier
// TODO: needs the tiletype filter!
// TODO: tile override materials
// TODO: material types, trees, ice, constructions
// TODO: GUI
#include <iostream>
#include <stdint.h>
#include <string.h> // for memset
#include <vector>
#include <map>
using namespace std;
#include <DFTypes.h>
#include <DFTileTypes.h>
#include <DFHackAPI.h>
int main (int argc, const char* argv[])
{
bool showhidden = false;
bool showbaselayers = false;
for(int i = 0; i < argc; i++)
{
string test = argv[i];
if(test == "-a")
{
showhidden = true;
}
else if(test == "-b")
{
showbaselayers = true;
}
else if(test == "-ab" || test == "-ba")
{
showhidden = true;
showbaselayers = true;
}
}
uint32_t x_max,y_max,z_max;
uint16_t tiletypes[16][16];
t_designation designations[16][16];
uint8_t regionoffsets[16];
map <int16_t, uint32_t> materials;
materials.clear();
vector<t_matgloss> stonetypes;
vector< vector <uint16_t> > layerassign;
// init the API
DFHackAPI DF("Memory.xml");
// attach
if(!DF.Attach())
{
cerr << "DF not found" << endl;
return 1;
}
// init the map
DF.InitMap();
DF.getSize(x_max,y_max,z_max);
// get stone matgloss mapping
if(!DF.ReadStoneMatgloss(stonetypes))
{
//DF.DestroyMap();
cerr << "Can't get the materials." << endl;
return 1;
}
// get region geology
if(!DF.ReadGeology( layerassign ))
{
cerr << "Can't get region geology." << endl;
return 1;
}
int16_t tempvein [16][16];
vector <t_vein> veins;
// 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(!DF.isValidBlock(x,y,z))
continue;
// read data
DF.ReadTileTypes(x,y,z, (uint16_t *) tiletypes);
DF.ReadDesignations(x,y,z, (uint32_t *) designations);
memset(tempvein, -1, sizeof(tempvein));
veins.clear();
DF.ReadVeins(x,y,z,veins);
if(showbaselayers)
{
DF.ReadRegionOffsets(x,y,z, regionoffsets);
// get the layer materials
for(uint32_t xx = 0;xx<16;xx++)
{
for (uint32_t yy = 0; yy< 16;yy++)
{
tempvein[xx][yy] =
layerassign
[regionoffsets[designations[xx][yy].bits.biome]]
[designations[xx][yy].bits.geolayer_index];
}
}
}
// for each vein
for(int i = 0; i < veins.size();i++)
{
//iterate through vein rows
for(uint32_t j = 0;j<16;j++)
{
//iterate through the bits
for (uint32_t k = 0; k< 16;k++)
{
// and the bit array with a one-bit mask, check if the bit is set
bool set = ((1 << k) & veins[i].assignment[j]) >> k;
if(set)
{
// store matgloss
tempvein[k][j] = veins[i].type;
}
}
}
}
// count the material types
for(uint32_t xi = 0 ; xi< 16 ; xi++)
{
for(uint32_t yi = 0 ; yi< 16 ; yi++)
{
// hidden tiles are ignored unless '-a' is provided on the command line
// non-wall tiles are ignored
if(designations[xi][yi].bits.hidden && !showhidden || !isWallTerrain(tiletypes[xi][yi]))
continue;
if(tempvein[xi][yi] < 0)
continue;
if(materials.count(tempvein[xi][yi]))
{
materials[tempvein[xi][yi]] += 1;
}
else
{
materials[tempvein[xi][yi]] = 1;
}
}
}
}
}
}
// print report
map<int16_t, uint32_t>::iterator p;
for(p = materials.begin(); p != materials.end(); p++)
{
cout << stonetypes[p->first].id << " : " << p->second << endl;
}
return 0;
}

@ -0,0 +1,50 @@
// This is a reveal program. It reveals the map.
#include <iostream>
#include <stdint.h>
#include <vector>
using namespace std;
#include <DFTypes.h>
#include <DFHackAPI.h>
int main (void)
{
uint32_t x_max,y_max,z_max;
uint32_t num_blocks = 0;
uint32_t bytes_read = 0;
t_designation designations[256];
DFHackAPI DF("Memory.xml");
if(!DF.Attach())
{
cerr << "DF not found" << endl;
return 1;
}
DF.InitMap();
DF.getSize(x_max,y_max,z_max);
// 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(DF.isValidBlock(x,y,z))
{
// read block designations
DF.ReadDesignations(x,y,z, (uint32_t *) designations);
// change the hidden flag to 0
for (uint32_t i = 0; i < 256;i++)
{
designations[i].bits.hidden = 0;
}
// write the designations back
DF.WriteDesignations(x,y,z, (uint32_t *) designations);
}
}
}
}
return 0;
}