summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Mrázek2009-09-14 00:02:46 +0000
committerPetr Mrázek2009-09-14 00:02:46 +0000
commitfac88478bd72056e4043e73ff1e8832ce1474a63 (patch)
treec9ca5f8e0bf10ec0999ef6e86c08f90fc3d7828a
parent52f768f6c53603415e4e6f949bb990a5da6b0483 (diff)
downloaddfhack-fac88478bd72056e4043e73ff1e8832ce1474a63.tar.gz
dfhack-fac88478bd72056e4043e73ff1e8832ce1474a63.tar.bz2
dfhack-fac88478bd72056e4043e73ff1e8832ce1474a63.tar.xz
code moved from khazad
-rw-r--r--CMakeLists.txt30
-rw-r--r--COMPILE55
-rw-r--r--LICENSE21
-rw-r--r--README47
-rw-r--r--dfhack.kdev43
-rw-r--r--library/CMakeLists.txt25
-rw-r--r--library/DFCommon.h63
-rw-r--r--library/DFDataModel.cpp105
-rw-r--r--library/DFDataModel.h54
-rw-r--r--library/DFHackAPI.cpp596
-rw-r--r--library/DFHackAPI.h160
-rw-r--r--library/DFMemAccess.h34
-rw-r--r--library/DFMemInfo.cpp382
-rw-r--r--library/DFMemInfo.h113
-rw-r--r--library/DFProcess.cpp160
-rw-r--r--library/DFProcessManager.cpp526
-rw-r--r--library/DFProcessManager.h97
-rw-r--r--library/DFTileTypes.cpp1024
-rw-r--r--library/DFTileTypes.h37
-rw-r--r--library/DFTypes.h250
-rw-r--r--library/DFVector.h67
-rw-r--r--library/LinuxMemAccess.h173
-rw-r--r--library/WindowsMemAccess.h156
-rw-r--r--library/deprecated/DfMap.cpp661
-rw-r--r--library/deprecated/DfMap.h204
-rw-r--r--library/deprecated/DfMapHeader.h41
-rw-r--r--library/deprecated/Extract.cpp433
-rw-r--r--library/deprecated/Extract.h51
-rw-r--r--library/deprecated/LoadSave.cpp188
-rw-r--r--library/deprecated/LoadSaveV1.cpp106
-rw-r--r--library/deprecated/LoadSaveV2.cpp196
-rw-r--r--library/deprecated/ZlibHelper.h160
-rw-r--r--library/md5/md5.cpp332
-rw-r--r--library/md5/md5.h92
-rw-r--r--library/md5/md5wrapper.cpp140
-rw-r--r--library/md5/md5wrapper.h73
-rw-r--r--library/tinyxml/tinystr.cpp116
-rw-r--r--library/tinyxml/tinystr.h319
-rw-r--r--library/tinyxml/tinyxml.cpp1888
-rw-r--r--library/tinyxml/tinyxml.h1802
-rw-r--r--library/tinyxml/tinyxmlerror.cpp53
-rw-r--r--library/tinyxml/tinyxmlparser.cpp1638
-rw-r--r--output/Memory.xml553
-rw-r--r--tools/CMakeLists.txt22
-rw-r--r--tools/cleanmap.cpp50
-rw-r--r--tools/expbench.cpp50
-rw-r--r--tools/prospector.cpp168
-rw-r--r--tools/reveal.cpp50
48 files changed, 13564 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..ab8f9569
--- /dev/null
+++ b/CMakeLists.txt
@@ -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) \ No newline at end of file
diff --git a/COMPILE b/COMPILE
new file mode 100644
index 00000000..19a5d2e5
--- /dev/null
+++ b/COMPILE
@@ -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. \ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..5b904f71
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/README b/README
new file mode 100644
index 00000000..d28c1d10
--- /dev/null
+++ b/README
@@ -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. \ No newline at end of file
diff --git a/dfhack.kdev4 b/dfhack.kdev4
new file mode 100644
index 00000000..771cc037
--- /dev/null
+++ b/dfhack.kdev4
@@ -0,0 +1,3 @@
+[Project]
+Manager=KDevCMakeManager
+Name=dfhack
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
new file mode 100644
index 00000000..cf98a488
--- /dev/null
+++ b/library/CMakeLists.txt
@@ -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}) \ No newline at end of file
diff --git a/library/DFCommon.h b/library/DFCommon.h
new file mode 100644
index 00000000..025acf88
--- /dev/null
+++ b/library/DFCommon.h
@@ -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
diff --git a/library/DFDataModel.cpp b/library/DFDataModel.cpp
new file mode 100644
index 00000000..28205e8b
--- /dev/null
+++ b/library/DFDataModel.cpp
@@ -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);
+};
diff --git a/library/DFDataModel.h b/library/DFDataModel.h
new file mode 100644
index 00000000..5deac3af
--- /dev/null
+++ b/library/DFDataModel.h
@@ -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
diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp
new file mode 100644
index 00000000..8ce58616
--- /dev/null
+++ b/library/DFHackAPI.cpp
@@ -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;
+}
diff --git a/library/DFHackAPI.h b/library/DFHackAPI.h
new file mode 100644
index 00000000..7ab67bd7
--- /dev/null
+++ b/library/DFHackAPI.h
@@ -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
diff --git a/library/DFMemAccess.h b/library/DFMemAccess.h
new file mode 100644
index 00000000..de6a0bc9
--- /dev/null
+++ b/library/DFMemAccess.h
@@ -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
diff --git a/library/DFMemInfo.cpp b/library/DFMemInfo.cpp
new file mode 100644
index 00000000..da12d57b
--- /dev/null
+++ b/library/DFMemInfo.cpp
@@ -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;
+}
diff --git a/library/DFMemInfo.h b/library/DFMemInfo.h
new file mode 100644
index 00000000..1a695430
--- /dev/null
+++ b/library/DFMemInfo.h
@@ -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
diff --git a/library/DFProcess.cpp b/library/DFProcess.cpp
new file mode 100644
index 00000000..66ea5489
--- /dev/null
+++ b/library/DFProcess.cpp
@@ -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
+
diff --git a/library/DFProcessManager.cpp b/library/DFProcessManager.cpp
new file mode 100644
index 00000000..3fc92cd2
--- /dev/null
+++ b/library/DFProcessManager.cpp
@@ -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];
+ }
+}
diff --git a/library/DFProcessManager.h b/library/DFProcessManager.h
new file mode 100644
index 00000000..85a38ca1
--- /dev/null
+++ b/library/DFProcessManager.h
@@ -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
diff --git a/library/DFTileTypes.cpp b/library/DFTileTypes.cpp
new file mode 100644
index 00000000..b17c7aeb
--- /dev/null
+++ b/library/DFTileTypes.cpp
@@ -0,0 +1,1024 @@
+/*
+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 "DFTileTypes.h"
+
+bool isWallTerrain(int in)
+{
+ switch (in)
+ {
+ case 65: //stone fortification
+ case 79: //stone pillar
+ case 80: //lavastone pillar
+ case 81: //featstone pillar
+ case 82: //minstone pillar
+ case 83: //frozen liquid pillar
+ case 176: //stone wall worn1 (most worn)
+ case 177: //stone wall worn2 (sorta worn)
+ case 178: //stone wall worn3 (least worn)
+ case 219: //stone wall (not worn)
+ case 265: //soil wall
+ case 269: //lavastone wall rd2
+ case 270: //lavastone wall r2d
+ case 271: //lavastone wall r2u
+ case 272: //lavastone wall ru2
+ case 273: //lavastone wall l2u
+ case 274: //lavastone wall lu2
+ case 275: //lavastone wall l2d
+ case 276: //lavastone wall ld2
+ case 277: //lavastone wall lrud
+ case 278: //lavastone wall rud
+ case 279: //lavastone wall lrd
+ case 280: //lavastone wall lru
+ case 281: //lavastone wall lud
+ case 282: //lavastone wall rd
+ case 283: //lavastone wall ru
+ case 284: //lavastone wall lu
+ case 285: //lavastone wall ld
+ case 286: //lavastone wall ud
+ case 287: //lavastone wall lr
+ case 288: //featstone wall rd2
+ case 289: //featstone wall r2d
+ case 290: //featstone wall r2u
+ case 291: //featstone wall ru2
+ case 292: //featstone wall l2u
+ case 293: //featstone wall lu2
+ case 294: //featstone wall l2d
+ case 295: //featstone wall ld2
+ case 296: //featstone wall lrud
+ case 297: //featstone wall rud
+ case 298: //featstone wall lrd
+ case 299: //featstone wall lru
+ case 300: //featstone wall lud
+ case 301: //featstone wall rd
+ case 382: //featstone wall ru
+ case 303: //featstone wall lu
+ case 304: //featstone wall ld
+ case 305: //featstone wall ud
+ case 306: //featstone wall lr
+ case 307: //stone wall rd2
+ case 308: //stone wall r2d
+ case 309: //stone wall r2u
+ case 310: //stone wall ru2
+ case 311: //stone wall l2u
+ case 312: //stone wall lu2
+ case 313: //stone wall l2d
+ case 314: //stone wall ld2
+ case 315: //stone wall lrud
+ case 316: //stone wall rud
+ case 317: //stone wall lrd
+ case 318: //stone wall lru
+ case 319: //stone wall lud
+ case 320: //stone wall rd
+ case 321: //stone wall ru
+ case 322: //stone wall lu
+ case 323: //stone wall ld
+ case 324: //stone wall ud
+ case 325: //stone wall lr
+ case 326: //lavastone fortification
+ case 327: //featstone fortification
+ case 328: //lavastone wall worn1 (most worn)
+ case 329: //lavastone wall worn2 (middle worn)
+ case 330: //lavastone wall worn3 (least worn)
+ case 331: //lavastone wall
+ case 332: //featstone wall worn1 (most worn)
+ case 333: //featstone wall worn2 (middle worn)
+ case 334: //featstone wall worn3 (least worn)
+ case 335: //featstone wall
+ case 360: //frozen liquid fortification
+ case 361: //frozen liquid wall worn1 (most worn)
+ case 362: //frozen liquid wall worn2 (middle worn)
+ case 363: //frozen liquid wall worn3 (least worn)
+ case 364: //frozen liquid wall
+ case 417: //minstone wall rd2
+ case 418: //minstone wall r2d
+ case 419: //minstone wall r2u
+ case 420: //minstone wall ru2
+ case 421: //minstone wall l2u
+ case 422: //minstone wall lu2
+ case 423: //minstone wall l2d
+ case 424: //minstone wall ld2
+ case 425: //minstone wall lrud
+ case 426: //minstone wall rud
+ case 427: //minstone wall lrd
+ case 428: //minstone wall lru
+ case 429: //minstone wall lud
+ case 430: //minstone wall rd
+ case 431: //minstone wall ru
+ case 432: //minstone wall lu
+ case 433: //minstone wall ld
+ case 434: //minstone wall ud
+ case 435: //minstone wall lr
+ case 436: //minstone fortification
+ case 437: //minstone wall worn1
+ case 438: //minstone wall worn2
+ case 439: //minstone wall worn3
+ case 440: //minstone wall worn4
+ case 450: //frozen liquid wall rd2
+ case 451: //frozen liquid wall r2d
+ case 452: //frozen liquid wall r2u
+ case 453: //frozen liquid wall ru2
+ case 454: //frozen liquid wall l2u
+ case 455: //frozen liquid wall lu2
+ case 456: //frozen liquid wall l2d
+ case 457: //frozen liquid wall ld2
+ case 458: //frozen liquid wall lrud
+ case 459: //frozen liquid wall rud
+ case 460: //frozen liquid wall lrd
+ case 461: //frozen liquid wall lru
+ case 462: //frozen liquid wall lud
+ case 463: //frozen liquid wall rd
+ case 464: //frozen liquid wall ru
+ case 465: //frozen liquid wall lu
+ case 466: //frozen liquid wall ld
+ case 467: //frozen liquid wall ud
+ case 468: //frozen liquid wall lr
+ case 494: //constructed fortification
+ case 495: //constructed pillar
+ case 496: //constructed wall rd2
+ case 497: //constructed wall r2d
+ case 498: //constructed wall r2u
+ case 499: //constructed wall ru2
+ case 500: //constructed wall l2u
+ case 501: //constructed wall lu2
+ case 502: //constructed wall l2d
+ case 503: //constructed wall ld2
+ case 504: //constructed wall lrud
+ case 505: //constructed wall rud
+ case 506: //constructed wall lrd
+ case 507: //constructed wall lru
+ case 508: //constructed wall lud
+ case 509: //constructed wall rd
+ case 510: //constructed wall ru
+ case 511: //constructed wall lu
+ case 512: //constructed wall ld
+ case 513: //constructed wall ud
+ case 514: //constructed wall lr
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+bool isFloorTerrain(int in)
+{
+ switch (in)
+ {
+ case 2: //murky pool
+
+ case 19: //driftwood stack
+ case 24: //tree
+ // case 27: //up stair frozen liquid
+ case 34: //shrub
+ case 35: //Chasm
+ // case 38: //up stair lavastone
+ // case 41: //up stair soil
+ case 42: //eerie pit
+ case 43: //stone floor detailed
+ case 44: //lavastone floor detailed
+ case 45: //featstone? floor detailed
+ case 46: //minstone? floor detailed [calcite]
+ case 47: //frozen liquid floor detailed
+ /*
+ case 51: //up stair grass1 [muddy?]
+ case 54: //up stair grass2
+ case 57: //up stair stone
+ case 60: //up stair minstone
+ case 63: //up stair featstone
+ */
+ case 67: //campfire
+ case 70: //fire
+ /*
+ case 79: //stone pillar
+ case 80: //lavastone pillar
+ case 81: //featstone pillar
+ case 82: //minstone pillar
+ case 83: //frozen liquid pillar
+ */
+ case 89: //waterfall landing
+ case 90: //river source
+
+ case 231: //sapling
+ /*
+ case 233: //ramp grass dry
+ case 234: //ramp grass dead
+ case 235: //ramp grass1 [muddy?]
+ case 236: //ramp grass2
+ case 237: //ramp stone
+ case 238: //ramp lavastone
+ case 239: //ramp featstone
+ case 240: //ramp minstone
+ case 241: //ramp soil
+ */
+ case 242: //ash1
+ case 243: //ash2
+ case 244: //ash3
+ // frozen floors / ramps
+ case 245: //ramp frozen liquid
+ case 258: //frozen liquid 1
+ case 259: //frozen liquid 2
+ case 260: //frozen liquid 3
+ case 262: //frozen liquid 0
+ case 261: //furrowed soil [road?]
+// case 262: //Ice floor
+ case 264: //Lava bottom of map
+ case 336: //stone floor 1 (raw stone)
+ case 337: //stone floor 2 (raw stone)
+ case 338: //stone floor 3 (raw stone)
+ case 339: //stone floor 4 (raw stone)
+ case 340: //lavastone floor 1 (raw stone)
+ case 341: //lavastone floor 2 (raw stone)
+ case 342: //lavastone floor 3 (raw stone)
+ case 343: //lavastone floor 4 (raw stone)
+ case 344: //featstone floor 1 (raw stone)
+ case 345: //featstone floor 2 (raw stone)
+ case 346: //featstone floor 3 (raw stone)
+ case 347: //featstone floor 4 (raw stone)
+ case 348: //grass floor 1 (raw)
+ case 349: //grass floor 2 (raw)
+ case 350: //grass floor 3 (raw)
+ case 351: //grass floor 4 (raw)
+ case 352: //soil floor 1 (raw)
+ case 353: //soil floor 2 (raw)
+ case 354: //soil floor 3 (raw)
+ case 355: //soil floor 4 (raw)
+ case 356: //soil floor 1 wet (raw) [red sand?]
+ case 357: //soil floor 2 wet (raw) [red sand?]
+ case 358: //soil floor 3 wet (raw) [red sand?]
+ case 359: //soil floor 4 wet (raw) [red sand?]
+
+ case 365: //river n
+ case 366: //river s
+ case 367: //river e
+ case 368: //river w
+ case 369: //river nw
+ case 370: //river ne
+ case 371: //river sw
+ case 372: //river se
+
+ case 373: //stream wall n (below)
+ case 374: //stream wall s (below)
+ case 375: //stream wall e (below)
+ case 376: //stream wall w (below)
+ case 377: //stream wall nw (below)
+ case 378: //stream wall ne (below)
+ case 379: //stream wall sw (below)
+ case 380: //stream wall se (below)
+
+ case 387: //dry grass floor1
+ case 388: //dry grass floor2
+ case 389: //dry grass floor3
+ case 390: //dry grass floor4
+ case 391: //dead tree
+ case 392: //dead sapling
+ case 393: //dead shrub
+ case 394: //dead grass floor1
+ case 395: //dead grass floor2
+ case 396: //dead grass floor3
+ case 397: //dead grass floor4
+ case 398: //grass floor1b
+ case 399: //grass floor2b
+ case 400: //grass floor3b
+ case 401: //grass floor4b
+ case 402: //stone boulder
+ case 403: //lavastone boulder
+ case 404: //featstone boulder
+ case 405: //stone pebbles 1
+ case 406: //stone pebbles 2
+ case 407: //stone pebbles 3
+ case 408: //stone pebbles 4
+ case 409: //lavastone pebbles 1
+ case 410: //lavastone pebbles 2
+ case 411: //lavastone pebbles 3
+ case 412: //lavastone pebbles 4
+ case 413: //featstone pebbles 1
+ case 414: //featstone pebbles 2
+ case 415: //featstone pebbles 3
+ case 416: //featstone pebbles 4
+ case 441: //minstone floor 1 (cavern raw)
+ case 442: //minstone floor 2 (cavern raw)
+ case 443: //minstone floor 3 (cavern raw)
+ case 444: //minstone floor 4 (cavern raw)
+ case 445: //minstone boulder
+ case 446: //minstone pebbles 1
+ case 447: //minstone pebbles 2
+ case 448: //minstone pebbles 3
+ case 449: //minstone pebbles 4
+ case 493: //constructed floor detailed
+ //case 495: //constructed pillar
+ case 517: //stair up constructed
+ //case 518: //ramp constructed
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+bool isRampTerrain(int in)
+{
+ switch (in)
+ {
+ case 233: //ramp grass dry
+ case 234: //ramp grass dead
+ case 235: //ramp grass1 [muddy?]
+ case 236: //ramp grass2
+ case 237: //ramp stone
+ case 238: //ramp lavastone
+ case 239: //ramp featstone
+ case 240: //ramp minstone
+ case 241: //ramp soil
+ case 245: //ramp frozen liquid
+ case 518: //ramp constructed
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+bool isStairTerrain(int in)
+{
+ switch (in)
+ {
+ case 25: //up-down stair frozen liquid
+ case 26: //down stair frozen liquid
+ case 27: //up stair frozen liquid
+ case 36: //up-down stair lavastone
+ case 37: //down stair lavastone
+ case 38: //up stair lavastone
+ case 39: //up-down stair soil
+ case 40: //down stair soil
+ case 41: //up stair soil
+ case 49: //up-down stair grass1 [muddy?]
+ case 50: //down stair grass1 [muddy?]
+ case 51: //up stair grass1 [muddy?]
+ case 52: //up-down stair grass2
+ case 53: //down stair grass2
+ case 54: //up stair grass2
+ case 55: //up-down stair stone
+ case 56: //down stair stone
+ case 57: //up stair stone
+ case 58: //up-down stair minstone
+ case 59: //down stair minstone
+ case 60: //up stair minstone
+ case 61: //up-down stair featstone
+ case 62: //down stair featstone
+ case 63: //up stair featstone
+ case 515: //stair up-down constructed
+ case 516: //stair down constructed
+ case 517: //stair up constructed
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+bool isOpenTerrain(int in)
+{
+ switch (in)
+ {
+ //case -1: //uninitialized tile
+ case 1: //slope down
+ case 19: //driftwood stack
+ case 24: //tree
+ case 25: //up-down stair frozen liquid
+ case 26: //down stair frozen liquid
+ case 27: //up stair frozen liquid
+ case 32: //open space
+ case 34: //shrub
+ case 35: //chasm
+ case 36: //up-down stair lavastone
+ case 37: //down stair lavastone
+ case 38: //up stair lavastone
+ case 39: //up-down stair soil
+ case 40: //down stair soil
+ case 41: //up stair soil
+ case 42: //eerie pit
+ case 43: //stone floor detailed
+ case 44: //lavastone floor detailed
+ case 45: //featstone? floor detailed
+ case 46: //minstone? floor detailed [calcite]
+ case 47: //frozen liquid floor detailed
+ case 49: //up-down stair grass1 [muddy?]
+ case 50: //down stair grass1 [muddy?]
+ case 51: //up stair grass1 [muddy?]
+ case 52: //up-down stair grass2
+ case 53: //down stair grass2
+ case 54: //up stair grass2
+ case 55: //up-down stair stone
+ case 56: //down stair stone
+ case 57: //up stair stone
+ case 58: //up-down stair minstone
+ case 59: //down stair minstone
+ case 60: //up stair minstone
+ case 61: //up-down stair featstone
+ case 62: //down stair featstone
+ case 63: //up stair featstone
+ case 67: //campfire
+ case 70: //fire
+ /*
+ case 79: //stone pillar
+ case 80: //lavastone pillar
+ case 81: //featstone pillar
+ case 82: //minstone pillar
+ case 83: //frozen liquid pillar
+ */
+ case 231: //sapling
+ case 233: //ramp grass dry
+ case 234: //ramp grass dead
+ case 235: //ramp grass1 [muddy?]
+ case 236: //ramp grass2
+ case 237: //ramp stone
+ case 238: //ramp lavastone
+ case 239: //ramp featstone
+ case 240: //ramp minstone
+ case 241: //ramp soil
+ case 242: //ash1
+ case 243: //ash2
+ case 244: //ash3
+ case 245: //ramp frozen liquid
+ case 261: //furrowed soil [road?]
+ case 262: //Ice floor
+ case 336: //stone floor 1 (raw stone)
+ case 337: //stone floor 2 (raw stone)
+ case 338: //stone floor 3 (raw stone)
+ case 339: //stone floor 4 (raw stone)
+ case 340: //lavastone floor 1 (raw stone)
+ case 341: //lavastone floor 2 (raw stone)
+ case 342: //lavastone floor 3 (raw stone)
+ case 343: //lavastone floor 4 (raw stone)
+ case 344: //featstone floor 1 (raw stone)
+ case 345: //featstone floor 2 (raw stone)
+ case 346: //featstone floor 3 (raw stone)
+ case 347: //featstone floor 4 (raw stone)
+ case 348: //grass floor 1 (raw)
+ case 349: //grass floor 2 (raw)
+ case 350: //grass floor 3 (raw)
+ case 351: //grass floor 4 (raw)
+ case 352: //soil floor 1 (raw)
+ case 353: //soil floor 2 (raw)
+ case 354: //soil floor 3 (raw)
+ case 355: //soil floor 4 (raw)
+ case 356: //soil floor 1 wet (raw) [red sand?]
+ case 357: //soil floor 2 wet (raw) [red sand?]
+ case 358: //soil floor 3 wet (raw) [red sand?]
+ case 359: //soil floor 4 wet (raw) [red sand?]
+ case 381: //stream top (above)
+ case 387: //dry grass floor1
+ case 388: //dry grass floor2
+ case 389: //dry grass floor3
+ case 390: //dry grass floor4
+ case 391: //dead tree
+ case 392: //dead sapling
+ case 393: //dead shrub
+ case 394: //dead grass floor1
+ case 395: //dead grass floor2
+ case 396: //dead grass floor3
+ case 397: //dead grass floor4
+ case 398: //grass floor1b
+ case 399: //grass floor2b
+ case 400: //grass floor3b
+ case 401: //grass floor4b
+ case 402: //stone boulder
+ case 403: //lavastone boulder
+ case 404: //featstone boulder
+ case 405: //stone pebbles 1
+ case 406: //stone pebbles 2
+ case 407: //stone pebbles 3
+ case 408: //stone pebbles 4
+ case 409: //lavastone pebbles 1
+ case 410: //lavastone pebbles 2
+ case 411: //lavastone pebbles 3
+ case 412: //lavastone pebbles 4
+ case 413: //featstone pebbles 1
+ case 414: //featstone pebbles 2
+ case 415: //featstone pebbles 3
+ case 416: //featstone pebbles 4
+ case 441: //minstone floor 1 (cavern raw)
+ case 442: //minstone floor 2 (cavern raw)
+ case 443: //minstone floor 3 (cavern raw)
+ case 444: //minstone floor 4 (cavern raw)
+ case 445: //minstone boulder
+ case 446: //minstone pebbles 1
+ case 447: //minstone pebbles 2
+ case 448: //minstone pebbles 3
+ case 449: //minstone pebbles 4
+ case 493: //constructed floor detailed
+ //case 495: //constructed pillar
+ case 515: //stair up-down constructed
+ case 516: //stair down constructed
+ case 517: //stair up constructed
+ case 518: //ramp constructed
+
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+int picktexture(int in)
+{
+ switch ( in )
+ {
+ case 1: //slope down
+ return 3;
+
+ case 2: //murky pool
+ return 20;
+
+ case 19: //driftwood stack
+ return 8;
+
+ case 24: //tree
+ //return 3;
+ return 15;
+
+ case 25: //up-down stair frozen liquid
+ case 26: //down stair frozen liquid
+ case 27: //up stair frozen liquid
+ return 25;
+
+ case 32: //open space
+ return 5;
+
+ case 34: //shrub
+ return 14;
+
+ case 35: //chasm
+ return 31;
+
+ case 36: //up-down stair lavastone
+ case 37: //down stair lavastone
+ case 38: //up stair lavastone
+ return 32;
+
+ case 39: //up-down stair soil
+ case 40: //down stair soil
+ case 41: //up stair soil
+ return 10;
+
+ case 42: //eerie pit
+ return 31;
+
+ case 43: //stone floor detailed
+ return 7;
+
+ case 44: //lavastone floor detailed
+ return 32;
+
+ case 45: //featstone? floor detailed
+ return 18;
+
+ case 46: //minstone? floor detailed [calcite]
+ return 9;
+
+ case 47: //frozen liquid floor detailed
+ return 27;
+
+ case 49: //up-down stair grass1 [muddy?]
+ case 50: //down stair grass1 [muddy?]
+ case 51: //up stair grass1 [muddy?]
+ return 0;
+
+ case 52: //up-down stair grass2
+ case 53: //down stair grass2
+ case 54: //up stair grass2
+ return 0; //16;
+
+ case 55: //up-down stair stone
+ case 56: //down stair stone
+ case 57: //up stair stone
+ return 1;
+
+ case 58: //up-down stair minstone
+ case 59: //down stair minstone
+ case 60: //up stair minstone
+ return 9;
+
+ case 61: //up-down stair featstone
+ case 62: //down stair featstone
+ case 63: //up stair featstone
+ return 18;
+
+ case 65: //stone fortification
+ return 22;
+
+ case 67: //campfire
+ return 3;
+
+ case 70: //fire
+ return 3;
+
+ case 79: //stone pillar
+ return 1;
+
+ case 80: //lavastone pillar
+ return 32;
+
+ case 81: //featstone pillar
+ return 18;
+
+ case 82: //minstone pillar
+ return 9;
+
+ case 83: //frozen liquid pillar
+ return 27;
+
+ case 89: //waterfall landing
+ return 20;
+
+ case 90: //river source
+ return 20;
+
+ case 176: //stone wall worn1 (most worn)
+ case 177: //stone wall worn2 (sorta worn)
+ case 178: //stone wall worn3 (least worn)
+ case 219: //stone wall (not worn)
+ return 1;
+
+ case 231: //sapling
+ return 15;
+
+ case 233: //ramp grass dry
+ return 33;
+
+ case 234: //ramp grass dead
+ return 33;
+
+ case 235: //ramp grass1 [muddy?]
+ return 0;
+
+ case 236: //ramp grass2
+ return 0; //16;
+
+ case 237: //ramp stone
+ return 1;
+
+ case 238: //ramp lavastone
+ return 32;
+
+ case 239: //ramp featstone
+ return 18;
+
+ case 240: //ramp minstone
+ return 9;
+
+ case 241: //ramp soil
+ return 10;
+
+ case 242: //ash1
+ case 243: //ash2
+ case 244: //ash3
+ return 32;
+
+ case 245: //ramp frozen liquid
+ return 27;
+
+ case 258: //frozen liquid 1
+ case 259: //frozen liquid 2
+ case 260: //frozen liquid 3
+ return 25;
+
+ case 261: //furrowed soil [road?]
+ return 21;
+
+ case 262: //frozen liquid 0
+ return 25;
+
+ case 264: //lava
+ return 24;
+
+ case 265: //soil wall
+ return 10;
+
+ case 269: //lavastone wall rd2
+ case 270: //lavastone wall r2d
+ case 271: //lavastone wall r2u
+ case 272: //lavastone wall ru2
+ case 273: //lavastone wall l2u
+ case 274: //lavastone wall lu2
+ case 275: //lavastone wall l2d
+ case 276: //lavastone wall ld2
+ case 277: //lavastone wall lrud
+ case 278: //lavastone wall rud
+ case 279: //lavastone wall lrd
+ case 280: //lavastone wall lru
+ case 281: //lavastone wall lud
+ case 282: //lavastone wall rd
+ case 283: //lavastone wall ru
+ case 284: //lavastone wall lu
+ case 285: //lavastone wall ld
+ case 286: //lavastone wall ud
+ case 287: //lavastone wall lr
+ return 32;
+
+ case 288: //featstone wall rd2
+ case 289: //featstone wall r2d
+ case 290: //featstone wall r2u
+ case 291: //featstone wall ru2
+ case 292: //featstone wall l2u
+ case 293: //featstone wall lu2
+ case 294: //featstone wall l2d
+ case 295: //featstone wall ld2
+ case 296: //featstone wall lrud
+ case 297: //featstone wall rud
+ case 298: //featstone wall lrd
+ case 299: //featstone wall lru
+ case 300: //featstone wall lud
+ case 301: //featstone wall rd
+ case 382: //featstone wall ru
+ case 303: //featstone wall lu
+ case 304: //featstone wall ld
+ case 305: //featstone wall ud
+ case 306: //featstone wall lr
+ return 18;
+
+ case 307: //stone wall rd2
+ case 308: //stone wall r2d
+ case 309: //stone wall r2u
+ case 310: //stone wall ru2
+ case 311: //stone wall l2u
+ case 312: //stone wall lu2
+ case 313: //stone wall l2d
+ case 314: //stone wall ld2
+ case 315: //stone wall lrud
+ case 316: //stone wall rud
+ case 317: //stone wall lrd
+ case 318: //stone wall lru
+ case 319: //stone wall lud
+ case 320: //stone wall rd
+ case 321: //stone wall ru
+ case 322: //stone wall lu
+ case 323: //stone wall ld
+ case 324: //stone wall ud
+ case 325: //stone wall lr
+ return 1;
+
+ case 326: //lavastone fortification
+ return 32;
+
+ case 327: //featstone fortification
+ return 18;
+
+ case 328: //lavastone wall worn1 (most worn)
+ case 329: //lavastone wall worn2 (middle worn)
+ case 330: //lavastone wall worn3 (least worn)
+ case 331: //lavastone wall
+ return 32;
+
+ case 332: //featstone wall worn1 (most worn)
+ case 333: //featstone wall worn2 (middle worn)
+ case 334: //featstone wall worn3 (least worn)
+ case 335: //featstone wall
+ return 18;
+
+ case 336: //stone floor 1 (raw stone)
+ case 337: //stone floor 2 (raw stone)
+ case 338: //stone floor 3 (raw stone)
+ case 339: //stone floor 4 (raw stone)
+ return 17;
+
+ case 340: //lavastone floor 1 (raw stone)
+ case 341: //lavastone floor 2 (raw stone)
+ case 342: //lavastone floor 3 (raw stone)
+ case 343: //lavastone floor 4 (raw stone)
+ return 32;
+
+ case 344: //featstone floor 1 (raw stone)
+ case 345: //featstone floor 2 (raw stone)
+ case 346: //featstone floor 3 (raw stone)
+ case 347: //featstone floor 4 (raw stone)
+ return 18;
+
+ case 348: //grass floor 1 (raw)
+ case 349: //grass floor 2 (raw)
+ case 350: //grass floor 3 (raw)
+ case 351: //grass floor 4 (raw)
+ return 0;
+
+ case 352: //soil floor 1 (raw)
+ case 353: //soil floor 2 (raw)
+ case 354: //soil floor 3 (raw)
+ case 355: //soil floor 4 (raw)
+ return 10;
+
+ case 356: //soil floor 1 wet (raw) [red sand?]
+ case 357: //soil floor 2 wet (raw) [red sand?]
+ case 358: //soil floor 3 wet (raw) [red sand?]
+ case 359: //soil floor 4 wet (raw) [red sand?]
+ return 10;
+
+ case 360: //frozen liquid fortification
+ return 27;
+
+ case 361: //frozen liquid wall worn1 (most worn)
+ case 362: //frozen liquid wall worn2 (middle worn)
+ case 363: //frozen liquid wall worn3 (least worn)
+ case 364: //frozen liquid wall
+ return 25;
+
+ case 365: //river n
+ case 366: //river s
+ case 367: //river e
+ case 368: //river w
+ case 369: //river nw
+ case 370: //river ne
+ case 371: //river sw
+ case 372: //river se
+ return 19;
+
+ case 373: //stream wall n (below)
+ case 374: //stream wall s (below)
+ case 375: //stream wall e (below)
+ case 376: //stream wall w (below)
+ case 377: //stream wall nw (below)
+ case 378: //stream wall ne (below)
+ case 379: //stream wall sw (below)
+ case 380: //stream wall se (below)
+ case 381: //stream top (above)
+ return 19;
+
+ case 387: //dry grass floor1
+ case 388: //dry grass floor2
+ case 389: //dry grass floor3
+ case 390: //dry grass floor4
+ return 33;
+
+ case 391: //dead tree
+ case 392: //dead sapling
+ case 393: //dead shrub
+ return 13;
+
+ case 394: //dead grass floor1
+ case 395: //dead grass floor2
+ case 396: //dead grass floor3
+ case 397: //dead grass floor4
+ return 33;
+
+ case 398: //grass floor1b
+ case 399: //grass floor2b
+ case 400: //grass floor3b
+ case 401: //grass floor4b
+ return 0; //16;
+
+ case 402: //stone boulder
+ case 403: //lavastone boulder
+ case 404: //featstone boulder
+ return 18;
+
+ case 405: //stone pebbles 1
+ case 406: //stone pebbles 2
+ case 407: //stone pebbles 3
+ case 408: //stone pebbles 4
+ return 12;
+
+ case 409: //lavastone pebbles 1
+ case 410: //lavastone pebbles 2
+ case 411: //lavastone pebbles 3
+ case 412: //lavastone pebbles 4
+ return 12;
+
+ case 413: //featstone pebbles 1
+ case 414: //featstone pebbles 2
+ case 415: //featstone pebbles 3
+ case 416: //featstone pebbles 4
+ return 12;
+
+ case 417: //minstone wall rd2
+ case 418: //minstone wall r2d
+ case 419: //minstone wall r2u
+ case 420: //minstone wall ru2
+ case 421: //minstone wall l2u
+ case 422: //minstone wall lu2
+ case 423: //minstone wall l2d
+ case 424: //minstone wall ld2
+ case 425: //minstone wall lrud
+ case 426: //minstone wall rud
+ case 427: //minstone wall lrd
+ case 428: //minstone wall lru
+ case 429: //minstone wall lud
+ case 430: //minstone wall rd
+ case 431: //minstone wall ru
+ case 432: //minstone wall lu
+ case 433: //minstone wall ld
+ case 434: //minstone wall ud
+ case 435: //minstone wall lr
+ return 9;
+
+ case 436: //minstone fortification
+ return 21;
+
+ case 437: //minstone wall worn1
+ case 438: //minstone wall worn2
+ case 439: //minstone wall worn3
+ case 440: //minstone wall worn4
+ return 21;
+
+ case 441: //minstone floor 1 (cavern raw)
+ case 442: //minstone floor 2 (cavern raw)
+ case 443: //minstone floor 3 (cavern raw)
+ case 444: //minstone floor 4 (cavern raw)
+ return 9;
+
+ case 445: //minstone boulder
+ return 18;
+
+ case 446: //minstone pebbles 1
+ case 447: //minstone pebbles 2
+ case 448: //minstone pebbles 3
+ case 449: //minstone pebbles 4
+ return 12;
+
+ case 450: //frozen liquid wall rd2
+ case 451: //frozen liquid wall r2d
+ case 452: //frozen liquid wall r2u
+ case 453: //frozen liquid wall ru2
+ case 454: //frozen liquid wall l2u
+ case 455: //frozen liquid wall lu2
+ case 456: //frozen liquid wall l2d
+ case 457: //frozen liquid wall ld2
+ case 458: //frozen liquid wall lrud
+ case 459: //frozen liquid wall rud
+ case 460: //frozen liquid wall lrd
+ case 461: //frozen liquid wall lru
+ case 462: //frozen liquid wall lud
+ case 463: //frozen liquid wall rd
+ case 464: //frozen liquid wall ru
+ case 465: //frozen liquid wall lu
+ case 466: //frozen liquid wall ld
+ case 467: //frozen liquid wall ud
+ case 468: //frozen liquid wall lr
+ return 25;
+
+ case 493: //constructed floor detailed
+ return 7;
+
+ case 494: //constructed fortification
+ return 7;
+
+ case 495: //constructed pillar
+ return 7;
+
+ case 496: //constructed wall rd2
+ case 497: //constructed wall r2d
+ case 498: //constructed wall r2u
+ case 499: //constructed wall ru2
+ case 500: //constructed wall l2u
+ case 501: //constructed wall lu2
+ case 502: //constructed wall l2d
+ case 503: //constructed wall ld2
+ case 504: //constructed wall lrud
+ case 505: //constructed wall rud
+ case 506: //constructed wall lrd
+ case 507: //constructed wall lru
+ case 508: //constructed wall lud
+ case 509: //constructed wall rd
+ case 510: //constructed wall ru
+ case 511: //constructed wall lu
+ case 512: //constructed wall ld
+ case 513: //constructed wall ud
+ case 514: //constructed wall lr
+ return 22;
+
+ case 515: //stair up-down constructed
+ case 516: //stair down constructed
+ case 517: //stair up constructed
+ return 4;
+
+ case 518: //ramp constructed
+ return 4;
+
+ case -1: //not assigned memory
+ return 6;
+
+ default: //none of the above
+ return -1;
+ }
+
+ return 6;
+}
diff --git a/library/DFTileTypes.h b/library/DFTileTypes.h
new file mode 100644
index 00000000..0a195a72
--- /dev/null
+++ b/library/DFTileTypes.h
@@ -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
diff --git a/library/DFTypes.h b/library/DFTypes.h
new file mode 100644
index 00000000..2928e6d6
--- /dev/null
+++ b/library/DFTypes.h
@@ -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
diff --git a/library/DFVector.h b/library/DFVector.h
new file mode 100644
index 00000000..79704b4a
--- /dev/null
+++ b/library/DFVector.h
@@ -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
diff --git a/library/LinuxMemAccess.h b/library/LinuxMemAccess.h
new file mode 100644
index 00000000..7971a5eb
--- /dev/null
+++ b/library/LinuxMemAccess.h
@@ -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;
+}
diff --git a/library/WindowsMemAccess.h b/library/WindowsMemAccess.h
new file mode 100644
index 00000000..a9d77880
--- /dev/null
+++ b/library/WindowsMemAccess.h
@@ -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;
+}
diff --git a/library/deprecated/DfMap.cpp b/library/deprecated/DfMap.cpp
new file mode 100644
index 00000000..10feaf2a
--- /dev/null
+++ b/library/deprecated/DfMap.cpp
@@ -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;
+}
diff --git a/library/deprecated/DfMap.h b/library/deprecated/DfMap.h
new file mode 100644
index 00000000..9debe5e7
--- /dev/null
+++ b/library/deprecated/DfMap.h
@@ -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
diff --git a/library/deprecated/DfMapHeader.h b/library/deprecated/DfMapHeader.h
new file mode 100644
index 00000000..aa886c74
--- /dev/null
+++ b/library/deprecated/DfMapHeader.h
@@ -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
+
diff --git a/library/deprecated/Extract.cpp b/library/deprecated/Extract.cpp
new file mode 100644
index 00000000..9f4c61e5
--- /dev/null
+++ b/library/deprecated/Extract.cpp
@@ -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;
+}
diff --git a/library/deprecated/Extract.h b/library/deprecated/Extract.h
new file mode 100644
index 00000000..824de5f8
--- /dev/null
+++ b/library/deprecated/Extract.h
@@ -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
diff --git a/library/deprecated/LoadSave.cpp b/library/deprecated/LoadSave.cpp
new file mode 100644
index 00000000..8f887308
--- /dev/null
+++ b/library/deprecated/LoadSave.cpp
@@ -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;
+}
diff --git a/library/deprecated/LoadSaveV1.cpp b/library/deprecated/LoadSaveV1.cpp
new file mode 100644
index 00000000..84fe9bc6
--- /dev/null
+++ b/library/deprecated/LoadSaveV1.cpp
@@ -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;
+}
+
diff --git a/library/deprecated/LoadSaveV2.cpp b/library/deprecated/LoadSaveV2.cpp
new file mode 100644
index 00000000..69763ead
--- /dev/null
+++ b/library/deprecated/LoadSaveV2.cpp
@@ -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;
+}
+*/
diff --git a/library/deprecated/ZlibHelper.h b/library/deprecated/ZlibHelper.h
new file mode 100644
index 00000000..dc54d05f
--- /dev/null
+++ b/library/deprecated/ZlibHelper.h
@@ -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
diff --git a/library/md5/md5.cpp b/library/md5/md5.cpp
new file mode 100644
index 00000000..c791893a
--- /dev/null
+++ b/library/md5/md5.cpp
@@ -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
+ */
diff --git a/library/md5/md5.h b/library/md5/md5.h
new file mode 100644
index 00000000..1c4b5969
--- /dev/null
+++ b/library/md5/md5.h
@@ -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
+ */
diff --git a/library/md5/md5wrapper.cpp b/library/md5/md5wrapper.cpp
new file mode 100644
index 00000000..fbaf8ab4
--- /dev/null
+++ b/library/md5/md5wrapper.cpp
@@ -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
+ */
diff --git a/library/md5/md5wrapper.h b/library/md5/md5wrapper.h
new file mode 100644
index 00000000..65dd2564
--- /dev/null
+++ b/library/md5/md5wrapper.h
@@ -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
+ */
diff --git a/library/tinyxml/tinystr.cpp b/library/tinyxml/tinystr.cpp
new file mode 100644
index 00000000..68125071
--- /dev/null
+++ b/library/tinyxml/tinystr.cpp
@@ -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
diff --git a/library/tinyxml/tinystr.h b/library/tinyxml/tinystr.h
new file mode 100644
index 00000000..3c2aa9d5
--- /dev/null
+++ b/library/tinyxml/tinystr.h
@@ -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
diff --git a/library/tinyxml/tinyxml.cpp b/library/tinyxml/tinyxml.cpp
new file mode 100644
index 00000000..5de21f6d
--- /dev/null
+++ b/library/tinyxml/tinyxml.cpp
@@ -0,0 +1,1888 @@
+/*
+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 <ctype.h>
+
+#ifdef TIXML_USE_STL
+#include <sstream>
+#include <iostream>
+#endif
+
+#include "tinyxml.h"
+
+
+bool TiXmlBase::condenseWhiteSpace = true;
+
+// Microsoft compiler security
+FILE* TiXmlFOpen( const char* filename, const char* mode )
+{
+ #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+ FILE* fp = 0;
+ errno_t err = fopen_s( &fp, filename, mode );
+ if ( !err && fp )
+ return fp;
+ return 0;
+ #else
+ return fopen( filename, mode );
+ #endif
+}
+
+void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString )
+{
+ int i=0;
+
+ while( i<(int)str.length() )
+ {
+ unsigned char c = (unsigned char) str[i];
+
+ if ( c == '&'
+ && i < ( (int)str.length() - 2 )
+ && str[i+1] == '#'
+ && str[i+2] == 'x' )
+ {
+ // Hexadecimal character reference.
+ // Pass through unchanged.
+ // &#xA9; -- copyright symbol, for example.
+ //
+ // The -1 is a bug fix from Rob Laveaux. It keeps
+ // an overflow from happening if there is no ';'.
+ // There are actually 2 ways to exit this loop -
+ // while fails (error case) and break (semicolon found).
+ // However, there is no mechanism (currently) for
+ // this function to return an error.
+ while ( i<(int)str.length()-1 )
+ {
+ outString->append( str.c_str() + i, 1 );
+ ++i;
+ if ( str[i] == ';' )
+ break;
+ }
+ }
+ else if ( c == '&' )
+ {
+ outString->append( entity[0].str, entity[0].strLength );
+ ++i;
+ }
+ else if ( c == '<' )
+ {
+ outString->append( entity[1].str, entity[1].strLength );
+ ++i;
+ }
+ else if ( c == '>' )
+ {
+ outString->append( entity[2].str, entity[2].strLength );
+ ++i;
+ }
+ else if ( c == '\"' )
+ {
+ outString->append( entity[3].str, entity[3].strLength );
+ ++i;
+ }
+ else if ( c == '\'' )
+ {
+ outString->append( entity[4].str, entity[4].strLength );
+ ++i;
+ }
+ else if ( c < 32 )
+ {
+ // Easy pass at non-alpha/numeric/symbol
+ // Below 32 is symbolic.
+ char buf[ 32 ];
+
+ #if defined(TIXML_SNPRINTF)
+ TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) );
+ #else
+ sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
+ #endif
+
+ //*ME: warning C4267: convert 'size_t' to 'int'
+ //*ME: Int-Cast to make compiler happy ...
+ outString->append( buf, (int)strlen( buf ) );
+ ++i;
+ }
+ else
+ {
+ //char realc = (char) c;
+ //outString->append( &realc, 1 );
+ *outString += (char) c; // somewhat more efficient function call.
+ ++i;
+ }
+ }
+}
+
+
+TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()
+{
+ parent = 0;
+ type = _type;
+ firstChild = 0;
+ lastChild = 0;
+ prev = 0;
+ next = 0;
+}
+
+
+TiXmlNode::~TiXmlNode()
+{
+ TiXmlNode* node = firstChild;
+ TiXmlNode* temp = 0;
+
+ while ( node )
+ {
+ temp = node;
+ node = node->next;
+ delete temp;
+ }
+}
+
+
+void TiXmlNode::CopyTo( TiXmlNode* target ) const
+{
+ target->SetValue (value.c_str() );
+ target->userData = userData;
+}
+
+
+void TiXmlNode::Clear()
+{
+ TiXmlNode* node = firstChild;
+ TiXmlNode* temp = 0;
+
+ while ( node )
+ {
+ temp = node;
+ node = node->next;
+ delete temp;
+ }
+
+ firstChild = 0;
+ lastChild = 0;
+}
+
+
+TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
+{
+ assert( node->parent == 0 || node->parent == this );
+ assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );
+
+ if ( node->Type() == TiXmlNode::DOCUMENT )
+ {
+ delete node;
+ if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+
+ node->parent = this;
+
+ node->prev = lastChild;
+ node->next = 0;
+
+ if ( lastChild )
+ lastChild->next = node;
+ else
+ firstChild = node; // it was an empty list.
+
+ lastChild = node;
+ return node;
+}
+
+
+TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
+{
+ if ( addThis.Type() == TiXmlNode::DOCUMENT )
+ {
+ if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+ TiXmlNode* node = addThis.Clone();
+ if ( !node )
+ return 0;
+
+ return LinkEndChild( node );
+}
+
+
+TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
+{
+ if ( !beforeThis || beforeThis->parent != this ) {
+ return 0;
+ }
+ if ( addThis.Type() == TiXmlNode::DOCUMENT )
+ {
+ if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+
+ TiXmlNode* node = addThis.Clone();
+ if ( !node )
+ return 0;
+ node->parent = this;
+
+ node->next = beforeThis;
+ node->prev = beforeThis->prev;
+ if ( beforeThis->prev )
+ {
+ beforeThis->prev->next = node;
+ }
+ else
+ {
+ assert( firstChild == beforeThis );
+ firstChild = node;
+ }
+ beforeThis->prev = node;
+ return node;
+}
+
+
+TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
+{
+ if ( !afterThis || afterThis->parent != this ) {
+ return 0;
+ }
+ if ( addThis.Type() == TiXmlNode::DOCUMENT )
+ {
+ if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+
+ TiXmlNode* node = addThis.Clone();
+ if ( !node )
+ return 0;
+ node->parent = this;
+
+ node->prev = afterThis;
+ node->next = afterThis->next;
+ if ( afterThis->next )
+ {
+ afterThis->next->prev = node;
+ }
+ else
+ {
+ assert( lastChild == afterThis );
+ lastChild = node;
+ }
+ afterThis->next = node;
+ return node;
+}
+
+
+TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
+{
+ if ( replaceThis->parent != this )
+ return 0;
+
+ TiXmlNode* node = withThis.Clone();
+ if ( !node )
+ return 0;
+
+ node->next = replaceThis->next;
+ node->prev = replaceThis->prev;
+
+ if ( replaceThis->next )
+ replaceThis->next->prev = node;
+ else
+ lastChild = node;
+
+ if ( replaceThis->prev )
+ replaceThis->prev->next = node;
+ else
+ firstChild = node;
+
+ delete replaceThis;
+ node->parent = this;
+ return node;
+}
+
+
+bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
+{
+ if ( removeThis->parent != this )
+ {
+ assert( 0 );
+ return false;
+ }
+
+ if ( removeThis->next )
+ removeThis->next->prev = removeThis->prev;
+ else
+ lastChild = removeThis->prev;
+
+ if ( removeThis->prev )
+ removeThis->prev->next = removeThis->next;
+ else
+ firstChild = removeThis->next;
+
+ delete removeThis;
+ return true;
+}
+
+const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const
+{
+ const TiXmlNode* node;
+ for ( node = firstChild; node; node = node->next )
+ {
+ if ( strcmp( node->Value(), _value ) == 0 )
+ return node;
+ }
+ return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const
+{
+ const TiXmlNode* node;
+ for ( node = lastChild; node; node = node->prev )
+ {
+ if ( strcmp( node->Value(), _value ) == 0 )
+ return node;
+ }
+ return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
+{
+ if ( !previous )
+ {
+ return FirstChild();
+ }
+ else
+ {
+ assert( previous->parent == this );
+ return previous->NextSibling();
+ }
+}
+
+
+const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const
+{
+ if ( !previous )
+ {
+ return FirstChild( val );
+ }
+ else
+ {
+ assert( previous->parent == this );
+ return previous->NextSibling( val );
+ }
+}
+
+
+const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const
+{
+ const TiXmlNode* node;
+ for ( node = next; node; node = node->next )
+ {
+ if ( strcmp( node->Value(), _value ) == 0 )
+ return node;
+ }
+ return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const
+{
+ const TiXmlNode* node;
+ for ( node = prev; node; node = node->prev )
+ {
+ if ( strcmp( node->Value(), _value ) == 0 )
+ return node;
+ }
+ return 0;
+}
+
+
+void TiXmlElement::RemoveAttribute( const char * name )
+{
+ #ifdef TIXML_USE_STL
+ TIXML_STRING str( name );
+ TiXmlAttribute* node = attributeSet.Find( str );
+ #else
+ TiXmlAttribute* node = attributeSet.Find( name );
+ #endif
+ if ( node )
+ {
+ attributeSet.Remove( node );
+ delete node;
+ }
+}
+
+const TiXmlElement* TiXmlNode::FirstChildElement() const
+{
+ const TiXmlNode* node;
+
+ for ( node = FirstChild();
+ node;
+ node = node->NextSibling() )
+ {
+ if ( node->ToElement() )
+ return node->ToElement();
+ }
+ return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const
+{
+ const TiXmlNode* node;
+
+ for ( node = FirstChild( _value );
+ node;
+ node = node->NextSibling( _value ) )
+ {
+ if ( node->ToElement() )
+ return node->ToElement();
+ }
+ return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::NextSiblingElement() const
+{
+ const TiXmlNode* node;
+
+ for ( node = NextSibling();
+ node;
+ node = node->NextSibling() )
+ {
+ if ( node->ToElement() )
+ return node->ToElement();
+ }
+ return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const
+{
+ const TiXmlNode* node;
+
+ for ( node = NextSibling( _value );
+ node;
+ node = node->NextSibling( _value ) )
+ {
+ if ( node->ToElement() )
+ return node->ToElement();
+ }
+ return 0;
+}
+
+
+const TiXmlDocument* TiXmlNode::GetDocument() const
+{
+ const TiXmlNode* node;
+
+ for( node = this; node; node = node->parent )
+ {
+ if ( node->ToDocument() )
+ return node->ToDocument();
+ }
+ return 0;
+}
+
+
+TiXmlElement::TiXmlElement (const char * _value)
+ : TiXmlNode( TiXmlNode::ELEMENT )
+{
+ firstChild = lastChild = 0;
+ value = _value;
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlElement::TiXmlElement( const std::string& _value )
+ : TiXmlNode( TiXmlNode::ELEMENT )
+{
+ firstChild = lastChild = 0;
+ value = _value;
+}
+#endif
+
+
+TiXmlElement::TiXmlElement( const TiXmlElement& copy)
+ : TiXmlNode( TiXmlNode::ELEMENT )
+{
+ firstChild = lastChild = 0;
+ copy.CopyTo( this );
+}
+
+
+void TiXmlElement::operator=( const TiXmlElement& base )
+{
+ ClearThis();
+ base.CopyTo( this );
+}
+
+
+TiXmlElement::~TiXmlElement()
+{
+ ClearThis();
+}
+
+
+void TiXmlElement::ClearThis()
+{
+ Clear();
+ while( attributeSet.First() )
+ {
+ TiXmlAttribute* node = attributeSet.First();
+ attributeSet.Remove( node );
+ delete node;
+ }
+}
+
+
+const char* TiXmlElement::Attribute( const char* name ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( node )
+ return node->Value();
+ return 0;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( node )
+ return &node->ValueStr();
+ return 0;
+}
+#endif
+
+
+const char* TiXmlElement::Attribute( const char* name, int* i ) const
+{
+ const char* s = Attribute( name );
+ if ( i )
+ {
+ if ( s ) {
+ *i = atoi( s );
+ }
+ else {
+ *i = 0;
+ }
+ }
+ return s;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const
+{
+ const std::string* s = Attribute( name );
+ if ( i )
+ {
+ if ( s ) {
+ *i = atoi( s->c_str() );
+ }
+ else {
+ *i = 0;
+ }
+ }
+ return s;
+}
+#endif
+
+
+const char* TiXmlElement::Attribute( const char* name, double* d ) const
+{
+ const char* s = Attribute( name );
+ if ( d )
+ {
+ if ( s ) {
+ *d = atof( s );
+ }
+ else {
+ *d = 0;
+ }
+ }
+ return s;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const
+{
+ const std::string* s = Attribute( name );
+ if ( d )
+ {
+ if ( s ) {
+ *d = atof( s->c_str() );
+ }
+ else {
+ *d = 0;
+ }
+ }
+ return s;
+}
+#endif
+
+
+int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+ return node->QueryIntValue( ival );
+}
+
+
+#ifdef TIXML_USE_STL
+int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+ return node->QueryIntValue( ival );
+}
+#endif
+
+
+int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+ return node->QueryDoubleValue( dval );
+}
+
+
+#ifdef TIXML_USE_STL
+int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const
+{
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+ return node->QueryDoubleValue( dval );
+}
+#endif
+
+
+void TiXmlElement::SetAttribute( const char * name, int val )
+{
+ char buf[64];
+ #if defined(TIXML_SNPRINTF)
+ TIXML_SNPRINTF( buf, sizeof(buf), "%d", val );
+ #else
+ sprintf( buf, "%d", val );
+ #endif
+ SetAttribute( name, buf );
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlElement::SetAttribute( const std::string& name, int val )
+{
+ std::ostringstream oss;
+ oss << val;
+ SetAttribute( name, oss.str() );
+}
+#endif
+
+
+void TiXmlElement::SetDoubleAttribute( const char * name, double val )
+{
+ char buf[256];
+ #if defined(TIXML_SNPRINTF)
+ TIXML_SNPRINTF( buf, sizeof(buf), "%f", val );
+ #else
+ sprintf( buf, "%f", val );
+ #endif
+ SetAttribute( name, buf );
+}
+
+
+void TiXmlElement::SetAttribute( const char * cname, const char * cvalue )
+{
+ #ifdef TIXML_USE_STL
+ TIXML_STRING _name( cname );
+ TIXML_STRING _value( cvalue );
+ #else
+ const char* _name = cname;
+ const char* _value = cvalue;
+ #endif
+
+ TiXmlAttribute* node = attributeSet.Find( _name );
+ if ( node )
+ {
+ node->SetValue( _value );
+ return;
+ }
+
+ TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue );
+ if ( attrib )
+ {
+ attributeSet.Add( attrib );
+ }
+ else
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ }
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value )
+{
+ TiXmlAttribute* node = attributeSet.Find( name );
+ if ( node )
+ {
+ node->SetValue( _value );
+ return;
+ }
+
+ TiXmlAttribute* attrib = new TiXmlAttribute( name, _value );
+ if ( attrib )
+ {
+ attributeSet.Add( attrib );
+ }
+ else
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ }
+}
+#endif
+
+
+void TiXmlElement::Print( FILE* cfile, int depth ) const
+{
+ int i;
+ assert( cfile );
+ for ( i=0; i<depth; i++ ) {
+ fprintf( cfile, " " );
+ }
+
+ fprintf( cfile, "<%s", value.c_str() );
+
+ const TiXmlAttribute* attrib;
+ for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
+ {
+ fprintf( cfile, " " );
+ attrib->Print( cfile, depth );
+ }
+
+ // There are 3 different formatting approaches:
+ // 1) An element without children is printed as a <foo /> node
+ // 2) An element with only a text child is printed as <foo> text </foo>
+ // 3) An element with children is printed on multiple lines.
+ TiXmlNode* node;
+ if ( !firstChild )
+ {
+ fprintf( cfile, " />" );
+ }
+ else if ( firstChild == lastChild && firstChild->ToText() )
+ {
+ fprintf( cfile, ">" );
+ firstChild->Print( cfile, depth + 1 );
+ fprintf( cfile, "</%s>", value.c_str() );
+ }
+ else
+ {
+ fprintf( cfile, ">" );
+
+ for ( node = firstChild; node; node=node->NextSibling() )
+ {
+ if ( !node->ToText() )
+ {
+ fprintf( cfile, "\n" );
+ }
+ node->Print( cfile, depth+1 );
+ }
+ fprintf( cfile, "\n" );
+ for( i=0; i<depth; ++i ) {
+ fprintf( cfile, " " );
+ }
+ fprintf( cfile, "</%s>", value.c_str() );
+ }
+}
+
+
+void TiXmlElement::CopyTo( TiXmlElement* target ) const
+{
+ // superclass:
+ TiXmlNode::CopyTo( target );
+
+ // Element class:
+ // Clone the attributes, then clone the children.
+ const TiXmlAttribute* attribute = 0;
+ for( attribute = attributeSet.First();
+ attribute;
+ attribute = attribute->Next() )
+ {
+ target->SetAttribute( attribute->Name(), attribute->Value() );
+ }
+
+ TiXmlNode* node = 0;
+ for ( node = firstChild; node; node = node->NextSibling() )
+ {
+ target->LinkEndChild( node->Clone() );
+ }
+}
+
+bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const
+{
+ if ( visitor->VisitEnter( *this, attributeSet.First() ) )
+ {
+ for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+ {
+ if ( !node->Accept( visitor ) )
+ break;
+ }
+ }
+ return visitor->VisitExit( *this );
+}
+
+
+TiXmlNode* TiXmlElement::Clone() const
+{
+ TiXmlElement* clone = new TiXmlElement( Value() );
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+const char* TiXmlElement::GetText() const
+{
+ const TiXmlNode* child = this->FirstChild();
+ if ( child ) {
+ const TiXmlText* childText = child->ToText();
+ if ( childText ) {
+ return childText->Value();
+ }
+ }
+ return 0;
+}
+
+
+TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
+{
+ tabsize = 4;
+ useMicrosoftBOM = false;
+ ClearError();
+}
+
+TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
+{
+ tabsize = 4;
+ useMicrosoftBOM = false;
+ value = documentName;
+ ClearError();
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
+{
+ tabsize = 4;
+ useMicrosoftBOM = false;
+ value = documentName;
+ ClearError();
+}
+#endif
+
+
+TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT )
+{
+ copy.CopyTo( this );
+}
+
+
+void TiXmlDocument::operator=( const TiXmlDocument& copy )
+{
+ Clear();
+ copy.CopyTo( this );
+}
+
+
+bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
+{
+ // See STL_STRING_BUG below.
+ //StringToBuffer buf( value );
+
+ return LoadFile( Value(), encoding );
+}
+
+
+bool TiXmlDocument::SaveFile() const
+{
+ // See STL_STRING_BUG below.
+// StringToBuffer buf( value );
+//
+// if ( buf.buffer && SaveFile( buf.buffer ) )
+// return true;
+//
+// return false;
+ return SaveFile( Value() );
+}
+
+bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
+{
+ // There was a really terrifying little bug here. The code:
+ // value = filename
+ // in the STL case, cause the assignment method of the std::string to
+ // be called. What is strange, is that the std::string had the same
+ // address as it's c_str() method, and so bad things happen. Looks
+ // like a bug in the Microsoft STL implementation.
+ // Add an extra string to avoid the crash.
+ TIXML_STRING filename( _filename );
+ value = filename;
+
+ // reading in binary mode so that tinyxml can normalize the EOL
+ FILE* file = TiXmlFOpen( value.c_str (), "rb" );
+
+ if ( file )
+ {
+ bool result = LoadFile( file, encoding );
+ fclose( file );
+ return result;
+ }
+ else
+ {
+ SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return false;
+ }
+}
+
+bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
+{
+ if ( !file )
+ {
+ SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return false;
+ }
+
+ // Delete the existing data:
+ Clear();
+ location.Clear();
+
+ // Get the file size, so we can pre-allocate the string. HUGE speed impact.
+ long length = 0;
+ fseek( file, 0, SEEK_END );
+ length = ftell( file );
+ fseek( file, 0, SEEK_SET );
+
+ // Strange case, but good to handle up front.
+ if ( length <= 0 )
+ {
+ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return false;
+ }
+
+ // If we have a file, assume it is all one big XML file, and read it in.
+ // The document parser may decide the document ends sooner than the entire file, however.
+ TIXML_STRING data;
+ data.reserve( length );
+
+ // Subtle bug here. TinyXml did use fgets. But from the XML spec:
+ // 2.11 End-of-Line Handling
+ // <snip>
+ // <quote>
+ // ...the XML processor MUST behave as if it normalized all line breaks in external
+ // parsed entities (including the document entity) on input, before parsing, by translating
+ // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to
+ // a single #xA character.
+ // </quote>
+ //
+ // It is not clear fgets does that, and certainly isn't clear it works cross platform.
+ // Generally, you expect fgets to translate from the convention of the OS to the c/unix
+ // convention, and not work generally.
+
+ /*
+ while( fgets( buf, sizeof(buf), file ) )
+ {
+ data += buf;
+ }
+ */
+
+ char* buf = new char[ length+1 ];
+ buf[0] = 0;
+
+ if ( fread( buf, length, 1, file ) != 1 ) {
+ delete [] buf;
+ SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return false;
+ }
+
+ const char* lastPos = buf;
+ const char* p = buf;
+
+ buf[length] = 0;
+ while( *p ) {
+ assert( p < (buf+length) );
+ if ( *p == 0xa ) {
+ // Newline character. No special rules for this. Append all the characters
+ // since the last string, and include the newline.
+ data.append( lastPos, (p-lastPos+1) ); // append, include the newline
+ ++p; // move past the newline
+ lastPos = p; // and point to the new buffer (may be 0)
+ assert( p <= (buf+length) );
+ }
+ else if ( *p == 0xd ) {
+ // Carriage return. Append what we have so far, then
+ // handle moving forward in the buffer.
+ if ( (p-lastPos) > 0 ) {
+ data.append( lastPos, p-lastPos ); // do not add the CR
+ }
+ data += (char)0xa; // a proper newline
+
+ if ( *(p+1) == 0xa ) {
+ // Carriage return - new line sequence
+ p += 2;
+ lastPos = p;
+ assert( p <= (buf+length) );
+ }
+ else {
+ // it was followed by something else...that is presumably characters again.
+ ++p;
+ lastPos = p;
+ assert( p <= (buf+length) );
+ }
+ }
+ else {
+ ++p;
+ }
+ }
+ // Handle any left over characters.
+ if ( p-lastPos ) {
+ data.append( lastPos, p-lastPos );
+ }
+ delete [] buf;
+ buf = 0;
+
+ Parse( data.c_str(), 0, encoding );
+
+ if ( Error() )
+ return false;
+ else
+ return true;
+}
+
+
+bool TiXmlDocument::SaveFile( const char * filename ) const
+{
+ // The old c stuff lives on...
+ FILE* fp = TiXmlFOpen( filename, "w" );
+ if ( fp )
+ {
+ bool result = SaveFile( fp );
+ fclose( fp );
+ return result;
+ }
+ return false;
+}
+
+
+bool TiXmlDocument::SaveFile( FILE* fp ) const
+{
+ if ( useMicrosoftBOM )
+ {
+ const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+ const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+ const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+ fputc( TIXML_UTF_LEAD_0, fp );
+ fputc( TIXML_UTF_LEAD_1, fp );
+ fputc( TIXML_UTF_LEAD_2, fp );
+ }
+ Print( fp, 0 );
+ return (ferror(fp) == 0);
+}
+
+
+void TiXmlDocument::CopyTo( TiXmlDocument* target ) const
+{
+ TiXmlNode::CopyTo( target );
+
+ target->error = error;
+ target->errorId = errorId;
+ target->errorDesc = errorDesc;
+ target->tabsize = tabsize;
+ target->errorLocation = errorLocation;
+ target->useMicrosoftBOM = useMicrosoftBOM;
+
+ TiXmlNode* node = 0;
+ for ( node = firstChild; node; node = node->NextSibling() )
+ {
+ target->LinkEndChild( node->Clone() );
+ }
+}
+
+
+TiXmlNode* TiXmlDocument::Clone() const
+{
+ TiXmlDocument* clone = new TiXmlDocument();
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+void TiXmlDocument::Print( FILE* cfile, int depth ) const
+{
+ assert( cfile );
+ for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+ {
+ node->Print( cfile, depth );
+ fprintf( cfile, "\n" );
+ }
+}
+
+
+bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const
+{
+ if ( visitor->VisitEnter( *this ) )
+ {
+ for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+ {
+ if ( !node->Accept( visitor ) )
+ break;
+ }
+ }
+ return visitor->VisitExit( *this );
+}
+
+
+const TiXmlAttribute* TiXmlAttribute::Next() const
+{
+ // We are using knowledge of the sentinel. The sentinel
+ // have a value or name.
+ if ( next->value.empty() && next->name.empty() )
+ return 0;
+ return next;
+}
+
+/*
+TiXmlAttribute* TiXmlAttribute::Next()
+{
+ // We are using knowledge of the sentinel. The sentinel
+ // have a value or name.
+ if ( next->value.empty() && next->name.empty() )
+ return 0;
+ return next;
+}
+*/
+
+const TiXmlAttribute* TiXmlAttribute::Previous() const
+{
+ // We are using knowledge of the sentinel. The sentinel
+ // have a value or name.
+ if ( prev->value.empty() && prev->name.empty() )
+ return 0;
+ return prev;
+}
+
+/*
+TiXmlAttribute* TiXmlAttribute::Previous()
+{
+ // We are using knowledge of the sentinel. The sentinel
+ // have a value or name.
+ if ( prev->value.empty() && prev->name.empty() )
+ return 0;
+ return prev;
+}
+*/
+
+void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
+{
+ TIXML_STRING n, v;
+
+ EncodeString( name, &n );
+ EncodeString( value, &v );
+
+ if (value.find ('\"') == TIXML_STRING::npos) {
+ if ( cfile ) {
+ fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
+ }
+ if ( str ) {
+ (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\"";
+ }
+ }
+ else {
+ if ( cfile ) {
+ fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
+ }
+ if ( str ) {
+ (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'";
+ }
+ }
+}
+
+
+int TiXmlAttribute::QueryIntValue( int* ival ) const
+{
+ if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 )
+ return TIXML_SUCCESS;
+ return TIXML_WRONG_TYPE;
+}
+
+int TiXmlAttribute::QueryDoubleValue( double* dval ) const
+{
+ if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 )
+ return TIXML_SUCCESS;
+ return TIXML_WRONG_TYPE;
+}
+
+void TiXmlAttribute::SetIntValue( int _value )
+{
+ char buf [64];
+ #if defined(TIXML_SNPRINTF)
+ TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value);
+ #else
+ sprintf (buf, "%d", _value);
+ #endif
+ SetValue (buf);
+}
+
+void TiXmlAttribute::SetDoubleValue( double _value )
+{
+ char buf [256];
+ #if defined(TIXML_SNPRINTF)
+ TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value);
+ #else
+ sprintf (buf, "%lf", _value);
+ #endif
+ SetValue (buf);
+}
+
+int TiXmlAttribute::IntValue() const
+{
+ return atoi (value.c_str ());
+}
+
+double TiXmlAttribute::DoubleValue() const
+{
+ return atof (value.c_str ());
+}
+
+
+TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT )
+{
+ copy.CopyTo( this );
+}
+
+
+void TiXmlComment::operator=( const TiXmlComment& base )
+{
+ Clear();
+ base.CopyTo( this );
+}
+
+
+void TiXmlComment::Print( FILE* cfile, int depth ) const
+{
+ assert( cfile );
+ for ( int i=0; i<depth; i++ )
+ {
+ fprintf( cfile, " " );
+ }
+ fprintf( cfile, "<!--%s-->", value.c_str() );
+}
+
+
+void TiXmlComment::CopyTo( TiXmlComment* target ) const
+{
+ TiXmlNode::CopyTo( target );
+}
+
+
+bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlComment::Clone() const
+{
+ TiXmlComment* clone = new TiXmlComment();
+
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+void TiXmlText::Print( FILE* cfile, int depth ) const
+{
+ assert( cfile );
+ if ( cdata )
+ {
+ int i;
+ fprintf( cfile, "\n" );
+ for ( i=0; i<depth; i++ ) {
+ fprintf( cfile, " " );
+ }
+ fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() ); // unformatted output
+ }
+ else
+ {
+ TIXML_STRING buffer;
+ EncodeString( value, &buffer );
+ fprintf( cfile, "%s", buffer.c_str() );
+ }
+}
+
+
+void TiXmlText::CopyTo( TiXmlText* target ) const
+{
+ TiXmlNode::CopyTo( target );
+ target->cdata = cdata;
+}
+
+
+bool TiXmlText::Accept( TiXmlVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlText::Clone() const
+{
+ TiXmlText* clone = 0;
+ clone = new TiXmlText( "" );
+
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+TiXmlDeclaration::TiXmlDeclaration( const char * _version,
+ const char * _encoding,
+ const char * _standalone )
+ : TiXmlNode( TiXmlNode::DECLARATION )
+{
+ version = _version;
+ encoding = _encoding;
+ standalone = _standalone;
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlDeclaration::TiXmlDeclaration( const std::string& _version,
+ const std::string& _encoding,
+ const std::string& _standalone )
+ : TiXmlNode( TiXmlNode::DECLARATION )
+{
+ version = _version;
+ encoding = _encoding;
+ standalone = _standalone;
+}
+#endif
+
+
+TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
+ : TiXmlNode( TiXmlNode::DECLARATION )
+{
+ copy.CopyTo( this );
+}
+
+
+void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
+{
+ Clear();
+ copy.CopyTo( this );
+}
+
+
+void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
+{
+ if ( cfile ) fprintf( cfile, "<?xml " );
+ if ( str ) (*str) += "<?xml ";
+
+ if ( !version.empty() ) {
+ if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ());
+ if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; }
+ }
+ if ( !encoding.empty() ) {
+ if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
+ if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; }
+ }
+ if ( !standalone.empty() ) {
+ if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
+ if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; }
+ }
+ if ( cfile ) fprintf( cfile, "?>" );
+ if ( str ) (*str) += "?>";
+}
+
+
+void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
+{
+ TiXmlNode::CopyTo( target );
+
+ target->version = version;
+ target->encoding = encoding;
+ target->standalone = standalone;
+}
+
+
+bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlDeclaration::Clone() const
+{
+ TiXmlDeclaration* clone = new TiXmlDeclaration();
+
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+void TiXmlUnknown::Print( FILE* cfile, int depth ) const
+{
+ for ( int i=0; i<depth; i++ )
+ fprintf( cfile, " " );
+ fprintf( cfile, "<%s>", value.c_str() );
+}
+
+
+void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
+{
+ TiXmlNode::CopyTo( target );
+}
+
+
+bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const
+{
+ return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlUnknown::Clone() const
+{
+ TiXmlUnknown* clone = new TiXmlUnknown();
+
+ if ( !clone )
+ return 0;
+
+ CopyTo( clone );
+ return clone;
+}
+
+
+TiXmlAttributeSet::TiXmlAttributeSet()
+{
+ sentinel.next = &sentinel;
+ sentinel.prev = &sentinel;
+}
+
+
+TiXmlAttributeSet::~TiXmlAttributeSet()
+{
+ assert( sentinel.next == &sentinel );
+ assert( sentinel.prev == &sentinel );
+}
+
+
+void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
+{
+ #ifdef TIXML_USE_STL
+ assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set.
+ #else
+ assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set.
+ #endif
+
+ addMe->next = &sentinel;
+ addMe->prev = sentinel.prev;
+
+ sentinel.prev->next = addMe;
+ sentinel.prev = addMe;
+}
+
+void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
+{
+ TiXmlAttribute* node;
+
+ for( node = sentinel.next; node != &sentinel; node = node->next )
+ {
+ if ( node == removeMe )
+ {
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ node->next = 0;
+ node->prev = 0;
+ return;
+ }
+ }
+ assert( 0 ); // we tried to remove a non-linked attribute.
+}
+
+
+#ifdef TIXML_USE_STL
+const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const
+{
+ for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+ {
+ if ( node->name == name )
+ return node;
+ }
+ return 0;
+}
+
+/*
+TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name )
+{
+ for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+ {
+ if ( node->name == name )
+ return node;
+ }
+ return 0;
+}
+*/
+#endif
+
+
+const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const
+{
+ for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+ {
+ if ( strcmp( node->name.c_str(), name ) == 0 )
+ return node;
+ }
+ return 0;
+}
+
+/*
+TiXmlAttribute* TiXmlAttributeSet::Find( const char* name )
+{
+ for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+ {
+ if ( strcmp( node->name.c_str(), name ) == 0 )
+ return node;
+ }
+ return 0;
+}
+*/
+
+#ifdef TIXML_USE_STL
+std::istream& operator>> (std::istream & in, TiXmlNode & base)
+{
+ TIXML_STRING tag;
+ tag.reserve( 8 * 1000 );
+ base.StreamIn( &in, &tag );
+
+ base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
+ return in;
+}
+#endif
+
+
+#ifdef TIXML_USE_STL
+std::ostream& operator<< (std::ostream & out, const TiXmlNode & base)
+{
+ TiXmlPrinter printer;
+ printer.SetStreamPrinting();
+ base.Accept( &printer );
+ out << printer.Str();
+
+ return out;
+}
+
+
+std::string& operator<< (std::string& out, const TiXmlNode& base )
+{
+ TiXmlPrinter printer;
+ printer.SetStreamPrinting();
+ base.Accept( &printer );
+ out.append( printer.Str() );
+
+ return out;
+}
+#endif
+
+
+TiXmlHandle TiXmlHandle::FirstChild() const
+{
+ if ( node )
+ {
+ TiXmlNode* child = node->FirstChild();
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const
+{
+ if ( node )
+ {
+ TiXmlNode* child = node->FirstChild( value );
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChildElement() const
+{
+ if ( node )
+ {
+ TiXmlElement* child = node->FirstChildElement();
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const
+{
+ if ( node )
+ {
+ TiXmlElement* child = node->FirstChildElement( value );
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::Child( int count ) const
+{
+ if ( node )
+ {
+ int i;
+ TiXmlNode* child = node->FirstChild();
+ for ( i=0;
+ child && i<count;
+ child = child->NextSibling(), ++i )
+ {
+ // nothing
+ }
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const
+{
+ if ( node )
+ {
+ int i;
+ TiXmlNode* child = node->FirstChild( value );
+ for ( i=0;
+ child && i<count;
+ child = child->NextSibling( value ), ++i )
+ {
+ // nothing
+ }
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::ChildElement( int count ) const
+{
+ if ( node )
+ {
+ int i;
+ TiXmlElement* child = node->FirstChildElement();
+ for ( i=0;
+ child && i<count;
+ child = child->NextSiblingElement(), ++i )
+ {
+ // nothing
+ }
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const
+{
+ if ( node )
+ {
+ int i;
+ TiXmlElement* child = node->FirstChildElement( value );
+ for ( i=0;
+ child && i<count;
+ child = child->NextSiblingElement( value ), ++i )
+ {
+ // nothing
+ }
+ if ( child )
+ return TiXmlHandle( child );
+ }
+ return TiXmlHandle( 0 );
+}
+
+
+bool TiXmlPrinter::VisitEnter( const TiXmlDocument& )
+{
+ return true;
+}
+
+bool TiXmlPrinter::VisitExit( const TiXmlDocument& )
+{
+ return true;
+}
+
+bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute )
+{
+ DoIndent();
+ buffer += "<";
+ buffer += element.Value();
+
+ for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() )
+ {
+ buffer += " ";
+ attrib->Print( 0, 0, &buffer );
+ }
+
+ if ( !element.FirstChild() )
+ {
+ buffer += " />";
+ DoLineBreak();
+ }
+ else
+ {
+ buffer += ">";
+ if ( element.FirstChild()->ToText()
+ && element.LastChild() == element.FirstChild()
+ && element.FirstChild()->ToText()->CDATA() == false )
+ {
+ simpleTextPrint = true;
+ // no DoLineBreak()!
+ }
+ else
+ {
+ DoLineBreak();
+ }
+ }
+ ++depth;
+ return true;
+}
+
+
+bool TiXmlPrinter::VisitExit( const TiXmlElement& element )
+{
+ --depth;
+ if ( !element.FirstChild() )
+ {
+ // nothing.
+ }
+ else
+ {
+ if ( simpleTextPrint )
+ {
+ simpleTextPrint = false;
+ }
+ else
+ {
+ DoIndent();
+ }
+ buffer += "</";
+ buffer += element.Value();
+ buffer += ">";
+ DoLineBreak();
+ }
+ return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlText& text )
+{
+ if ( text.CDATA() )
+ {
+ DoIndent();
+ buffer += "<![CDATA[";
+ buffer += text.Value();
+ buffer += "]]>";
+ DoLineBreak();
+ }
+ else if ( simpleTextPrint )
+ {
+ TIXML_STRING str;
+ TiXmlBase::EncodeString( text.ValueTStr(), &str );
+ buffer += str;
+ }
+ else
+ {
+ DoIndent();
+ TIXML_STRING str;
+ TiXmlBase::EncodeString( text.ValueTStr(), &str );
+ buffer += str;
+ DoLineBreak();
+ }
+ return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration )
+{
+ DoIndent();
+ declaration.Print( 0, 0, &buffer );
+ DoLineBreak();
+ return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlComment& comment )
+{
+ DoIndent();
+ buffer += "<!--";
+ buffer += comment.Value();
+ buffer += "-->";
+ DoLineBreak();
+ return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown )
+{
+ DoIndent();
+ buffer += "<";
+ buffer += unknown.Value();
+ buffer += ">";
+ DoLineBreak();
+ return true;
+}
+
diff --git a/library/tinyxml/tinyxml.h b/library/tinyxml/tinyxml.h
new file mode 100644
index 00000000..c6f40cc2
--- /dev/null
+++ b/library/tinyxml/tinyxml.h
@@ -0,0 +1,1802 @@
+/*
+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.
+*/
+
+
+#ifndef TINYXML_INCLUDED
+#define TINYXML_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4530 )
+#pragma warning( disable : 4786 )
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+// Help out windows:
+#if defined( _DEBUG ) && !defined( DEBUG )
+#define DEBUG
+#endif
+
+#ifdef TIXML_USE_STL
+ #include <string>
+ #include <iostream>
+ #include <sstream>
+ #define TIXML_STRING std::string
+#else
+ #include "tinystr.h"
+ #define TIXML_STRING TiXmlString
+#endif
+
+// Deprecated library function hell. Compilers want to use the
+// new safe versions. This probably doesn't fully address the problem,
+// but it gets closer. There are too many compilers for me to fully
+// test. If you get compilation troubles, undefine TIXML_SAFE
+#define TIXML_SAFE
+
+#ifdef TIXML_SAFE
+ #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+ // Microsoft visual studio, version 2005 and higher.
+ #define TIXML_SNPRINTF _snprintf_s
+ #define TIXML_SNSCANF _snscanf_s
+ #define TIXML_SSCANF sscanf_s
+ #elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
+ // Microsoft visual studio, version 6 and higher.
+ //#pragma message( "Using _sn* functions." )
+ #define TIXML_SNPRINTF _snprintf
+ #define TIXML_SNSCANF _snscanf
+ #define TIXML_SSCANF sscanf
+ #elif defined(__GNUC__) && (__GNUC__ >= 3 )
+ // GCC version 3 and higher.s
+ //#warning( "Using sn* functions." )
+ #define TIXML_SNPRINTF snprintf
+ #define TIXML_SNSCANF snscanf
+ #define TIXML_SSCANF sscanf
+ #else
+ #define TIXML_SSCANF sscanf
+ #endif
+#endif
+
+class TiXmlDocument;
+class TiXmlElement;
+class TiXmlComment;
+class TiXmlUnknown;
+class TiXmlAttribute;
+class TiXmlText;
+class TiXmlDeclaration;
+class TiXmlParsingData;
+
+const int TIXML_MAJOR_VERSION = 2;
+const int TIXML_MINOR_VERSION = 5;
+const int TIXML_PATCH_VERSION = 3;
+
+/* Internal structure for tracking location of items
+ in the XML file.
+*/
+struct TiXmlCursor
+{
+ TiXmlCursor() { Clear(); }
+ void Clear() { row = col = -1; }
+
+ int row; // 0 based.
+ int col; // 0 based.
+};
+
+
+/**
+ If you call the Accept() method, it requires being passed a TiXmlVisitor
+ class to handle callbacks. For nodes that contain other nodes (Document, Element)
+ you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
+ are simple called with Visit().
+
+ If you return 'true' from a Visit method, recursive parsing will continue. If you return
+ false, <b>no children of this node or its sibilings</b> will be Visited.
+
+ All flavors of Visit methods have a default implementation that returns 'true' (continue
+ visiting). You need to only override methods that are interesting to you.
+
+ Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
+
+ You should never change the document from a callback.
+
+ @sa TiXmlNode::Accept()
+*/
+class TiXmlVisitor
+{
+public:
+ virtual ~TiXmlVisitor() {}
+
+ /// Visit a document.
+ virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; }
+ /// Visit a document.
+ virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; }
+
+ /// Visit an element.
+ virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; }
+ /// Visit an element.
+ virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; }
+
+ /// Visit a declaration
+ virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; }
+ /// Visit a text node
+ virtual bool Visit( const TiXmlText& /*text*/ ) { return true; }
+ /// Visit a comment node
+ virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; }
+ /// Visit an unknow node
+ virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; }
+};
+
+// Only used by Attribute::Query functions
+enum
+{
+ TIXML_SUCCESS,
+ TIXML_NO_ATTRIBUTE,
+ TIXML_WRONG_TYPE
+};
+
+
+// Used by the parsing routines.
+enum TiXmlEncoding
+{
+ TIXML_ENCODING_UNKNOWN,
+ TIXML_ENCODING_UTF8,
+ TIXML_ENCODING_LEGACY
+};
+
+const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN;
+
+/** TiXmlBase is a base class for every class in TinyXml.
+ It does little except to establish that TinyXml classes
+ can be printed and provide some utility functions.
+
+ In XML, the document and elements can contain
+ other elements and other types of nodes.
+
+ @verbatim
+ A Document can contain: Element (container or leaf)
+ Comment (leaf)
+ Unknown (leaf)
+ Declaration( leaf )
+
+ An Element can contain: Element (container or leaf)
+ Text (leaf)
+ Attributes (not on tree)
+ Comment (leaf)
+ Unknown (leaf)
+
+ A Decleration contains: Attributes (not on tree)
+ @endverbatim
+*/
+class TiXmlBase
+{
+ friend class TiXmlNode;
+ friend class TiXmlElement;
+ friend class TiXmlDocument;
+
+public:
+ TiXmlBase() : userData(0) {}
+ virtual ~TiXmlBase() {}
+
+ /** All TinyXml classes can print themselves to a filestream
+ or the string class (TiXmlString in non-STL mode, std::string
+ in STL mode.) Either or both cfile and str can be null.
+
+ This is a formatted print, and will insert
+ tabs and newlines.
+
+ (For an unformatted stream, use the << operator.)
+ */
+ virtual void Print( FILE* cfile, int depth ) const = 0;
+
+ /** The world does not agree on whether white space should be kept or
+ not. In order to make everyone happy, these global, static functions
+ are provided to set whether or not TinyXml will condense all white space
+ into a single space or not. The default is to condense. Note changing this
+ value is not thread safe.
+ */
+ static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; }
+
+ /// Return the current white space setting.
+ static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; }
+
+ /** Return the position, in the original source file, of this node or attribute.
+ The row and column are 1-based. (That is the first row and first column is
+ 1,1). If the returns values are 0 or less, then the parser does not have
+ a row and column value.
+
+ Generally, the row and column value will be set when the TiXmlDocument::Load(),
+ TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set
+ when the DOM was created from operator>>.
+
+ The values reflect the initial load. Once the DOM is modified programmatically
+ (by adding or changing nodes and attributes) the new values will NOT update to
+ reflect changes in the document.
+
+ There is a minor performance cost to computing the row and column. Computation
+ can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value.
+
+ @sa TiXmlDocument::SetTabSize()
+ */
+ int Row() const { return location.row + 1; }
+ int Column() const { return location.col + 1; } ///< See Row()
+
+ void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data.
+ void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data.
+ const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data.
+
+ // Table that returs, for a given lead byte, the total number of bytes
+ // in the UTF-8 sequence.
+ static const int utf8ByteTable[256];
+
+ virtual const char* Parse( const char* p,
+ TiXmlParsingData* data,
+ TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0;
+
+ /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc,
+ or they will be transformed into entities!
+ */
+ static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out );
+
+ enum
+ {
+ TIXML_NO_ERROR = 0,
+ TIXML_ERROR,
+ TIXML_ERROR_OPENING_FILE,
+ TIXML_ERROR_OUT_OF_MEMORY,
+ TIXML_ERROR_PARSING_ELEMENT,
+ TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME,
+ TIXML_ERROR_READING_ELEMENT_VALUE,
+ TIXML_ERROR_READING_ATTRIBUTES,
+ TIXML_ERROR_PARSING_EMPTY,
+ TIXML_ERROR_READING_END_TAG,
+ TIXML_ERROR_PARSING_UNKNOWN,
+ TIXML_ERROR_PARSING_COMMENT,
+ TIXML_ERROR_PARSING_DECLARATION,
+ TIXML_ERROR_DOCUMENT_EMPTY,
+ TIXML_ERROR_EMBEDDED_NULL,
+ TIXML_ERROR_PARSING_CDATA,
+ TIXML_ERROR_DOCUMENT_TOP_ONLY,
+
+ TIXML_ERROR_STRING_COUNT
+ };
+
+protected:
+
+ static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding );
+ inline static bool IsWhiteSpace( char c )
+ {
+ return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' );
+ }
+ inline static bool IsWhiteSpace( int c )
+ {
+ if ( c < 256 )
+ return IsWhiteSpace( (char) c );
+ return false; // Again, only truly correct for English/Latin...but usually works.
+ }
+
+ #ifdef TIXML_USE_STL
+ static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag );
+ static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag );
+ #endif
+
+ /* Reads an XML name into the string provided. Returns
+ a pointer just past the last character of the name,
+ or 0 if the function has an error.
+ */
+ static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding );
+
+ /* Reads text. Returns a pointer past the given end tag.
+ Wickedly complex options, but it keeps the (sensitive) code in one place.
+ */
+ static const char* ReadText( const char* in, // where to start
+ TIXML_STRING* text, // the string read
+ bool ignoreWhiteSpace, // whether to keep the white space
+ const char* endTag, // what ends this text
+ bool ignoreCase, // whether to ignore case in the end tag
+ TiXmlEncoding encoding ); // the current encoding
+
+ // If an entity has been found, transform it into a character.
+ static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding );
+
+ // Get a character, while interpreting entities.
+ // The length can be from 0 to 4 bytes.
+ inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding )
+ {
+ assert( p );
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ *length = utf8ByteTable[ *((const unsigned char*)p) ];
+ assert( *length >= 0 && *length < 5 );
+ }
+ else
+ {
+ *length = 1;
+ }
+
+ if ( *length == 1 )
+ {
+ if ( *p == '&' )
+ return GetEntity( p, _value, length, encoding );
+ *_value = *p;
+ return p+1;
+ }
+ else if ( *length )
+ {
+ //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe),
+ // and the null terminator isn't needed
+ for( int i=0; p[i] && i<*length; ++i ) {
+ _value[i] = p[i];
+ }
+ return p + (*length);
+ }
+ else
+ {
+ // Not valid text.
+ return 0;
+ }
+ }
+
+ // Return true if the next characters in the stream are any of the endTag sequences.
+ // Ignore case only works for english, and should only be relied on when comparing
+ // to English words: StringEqual( p, "version", true ) is fine.
+ static bool StringEqual( const char* p,
+ const char* endTag,
+ bool ignoreCase,
+ TiXmlEncoding encoding );
+
+ static const char* errorString[ TIXML_ERROR_STRING_COUNT ];
+
+ TiXmlCursor location;
+
+ /// Field containing a generic user pointer
+ void* userData;
+
+ // None of these methods are reliable for any language except English.
+ // Good for approximation, not great for accuracy.
+ static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding );
+ static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding );
+ inline static int ToLower( int v, TiXmlEncoding encoding )
+ {
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ if ( v < 128 ) return tolower( v );
+ return v;
+ }
+ else
+ {
+ return tolower( v );
+ }
+ }
+ static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
+
+private:
+ TiXmlBase( const TiXmlBase& ); // not implemented.
+ void operator=( const TiXmlBase& base ); // not allowed.
+
+ struct Entity
+ {
+ const char* str;
+ unsigned int strLength;
+ char chr;
+ };
+ enum
+ {
+ NUM_ENTITY = 5,
+ MAX_ENTITY_LENGTH = 6
+
+ };
+ static Entity entity[ NUM_ENTITY ];
+ static bool condenseWhiteSpace;
+};
+
+
+/** The parent class for everything in the Document Object Model.
+ (Except for attributes).
+ Nodes have siblings, a parent, and children. A node can be
+ in a document, or stand on its own. The type of a TiXmlNode
+ can be queried, and it can be cast to its more defined type.
+*/
+class TiXmlNode : public TiXmlBase
+{
+ friend class TiXmlDocument;
+ friend class TiXmlElement;
+
+public:
+ #ifdef TIXML_USE_STL
+
+ /** An input stream operator, for every class. Tolerant of newlines and
+ formatting, but doesn't expect them.
+ */
+ friend std::istream& operator >> (std::istream& in, TiXmlNode& base);
+
+ /** An output stream operator, for every class. Note that this outputs
+ without any newlines or formatting, as opposed to Print(), which
+ includes tabs and new lines.
+
+ The operator<< and operator>> are not completely symmetric. Writing
+ a node to a stream is very well defined. You'll get a nice stream
+ of output, without any extra whitespace or newlines.
+
+ But reading is not as well defined. (As it always is.) If you create
+ a TiXmlElement (for example) and read that from an input stream,
+ the text needs to define an element or junk will result. This is
+ true of all input streams, but it's worth keeping in mind.
+
+ A TiXmlDocument will read nodes until it reads a root element, and
+ all the children of that root element.
+ */
+ friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base);
+
+ /// Appends the XML node or attribute to a std::string.
+ friend std::string& operator<< (std::string& out, const TiXmlNode& base );
+
+ #endif
+
+ /** The types of XML nodes supported by TinyXml. (All the
+ unsupported types are picked up by UNKNOWN.)
+ */
+ enum NodeType
+ {
+ DOCUMENT,
+ ELEMENT,
+ COMMENT,
+ UNKNOWN,
+ TEXT,
+ DECLARATION,
+ TYPECOUNT
+ };
+
+ virtual ~TiXmlNode();
+
+ /** The meaning of 'value' changes for the specific type of
+ TiXmlNode.
+ @verbatim
+ Document: filename of the xml file
+ Element: name of the element
+ Comment: the comment text
+ Unknown: the tag contents
+ Text: the text string
+ @endverbatim
+
+ The subclasses will wrap this function.
+ */
+ const char *Value() const { return value.c_str (); }
+
+ #ifdef TIXML_USE_STL
+ /** Return Value() as a std::string. If you only use STL,
+ this is more efficient than calling Value().
+ Only available in STL mode.
+ */
+ const std::string& ValueStr() const { return value; }
+ #endif
+
+ const TIXML_STRING& ValueTStr() const { return value; }
+
+ /** Changes the value of the node. Defined as:
+ @verbatim
+ Document: filename of the xml file
+ Element: name of the element
+ Comment: the comment text
+ Unknown: the tag contents
+ Text: the text string
+ @endverbatim
+ */
+ void SetValue(const char * _value) { value = _value;}
+
+ #ifdef TIXML_USE_STL
+ /// STL std::string form.
+ void SetValue( const std::string& _value ) { value = _value; }
+ #endif
+
+ /// Delete all the children of this node. Does not affect 'this'.
+ void Clear();
+
+ /// One step up the DOM.
+ TiXmlNode* Parent() { return parent; }
+ const TiXmlNode* Parent() const { return parent; }
+
+ const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children.
+ TiXmlNode* FirstChild() { return firstChild; }
+ const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found.
+ /// The first child of this node with the matching 'value'. Will be null if none found.
+ TiXmlNode* FirstChild( const char * _value ) {
+ // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe)
+ // call the method, cast the return back to non-const.
+ return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value ));
+ }
+ const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children.
+ TiXmlNode* LastChild() { return lastChild; }
+
+ const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children.
+ TiXmlNode* LastChild( const char * _value ) {
+ return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value ));
+ }
+
+ #ifdef TIXML_USE_STL
+ const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form.
+ TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form.
+ const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form.
+ TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form.
+ #endif
+
+ /** An alternate way to walk the children of a node.
+ One way to iterate over nodes is:
+ @verbatim
+ for( child = parent->FirstChild(); child; child = child->NextSibling() )
+ @endverbatim
+
+ IterateChildren does the same thing with the syntax:
+ @verbatim
+ child = 0;
+ while( child = parent->IterateChildren( child ) )
+ @endverbatim
+
+ IterateChildren takes the previous child as input and finds
+ the next one. If the previous child is null, it returns the
+ first. IterateChildren will return null when done.
+ */
+ const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const;
+ TiXmlNode* IterateChildren( const TiXmlNode* previous ) {
+ return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) );
+ }
+
+ /// This flavor of IterateChildren searches for children with a particular 'value'
+ const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const;
+ TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) {
+ return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) );
+ }
+
+ #ifdef TIXML_USE_STL
+ const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form.
+ TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form.
+ #endif
+
+ /** Add a new node related to this. Adds a child past the LastChild.
+ Returns a pointer to the new object or NULL if an error occured.
+ */
+ TiXmlNode* InsertEndChild( const TiXmlNode& addThis );
+
+
+ /** Add a new node related to this. Adds a child past the LastChild.
+
+ NOTE: the node to be added is passed by pointer, and will be
+ henceforth owned (and deleted) by tinyXml. This method is efficient
+ and avoids an extra copy, but should be used with care as it
+ uses a different memory model than the other insert functions.
+
+ @sa InsertEndChild
+ */
+ TiXmlNode* LinkEndChild( TiXmlNode* addThis );
+
+ /** Add a new node related to this. Adds a child before the specified child.
+ Returns a pointer to the new object or NULL if an error occured.
+ */
+ TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );
+
+ /** Add a new node related to this. Adds a child after the specified child.
+ Returns a pointer to the new object or NULL if an error occured.
+ */
+ TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis );
+
+ /** Replace a child of this node.
+ Returns a pointer to the new object or NULL if an error occured.
+ */
+ TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );
+
+ /// Delete a child of this node.
+ bool RemoveChild( TiXmlNode* removeThis );
+
+ /// Navigate to a sibling node.
+ const TiXmlNode* PreviousSibling() const { return prev; }
+ TiXmlNode* PreviousSibling() { return prev; }
+
+ /// Navigate to a sibling node.
+ const TiXmlNode* PreviousSibling( const char * ) const;
+ TiXmlNode* PreviousSibling( const char *_prev ) {
+ return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) );
+ }
+
+ #ifdef TIXML_USE_STL
+ const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form.
+ TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form.
+ const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form.
+ TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form.
+ #endif
+
+ /// Navigate to a sibling node.
+ const TiXmlNode* NextSibling() const { return next; }
+ TiXmlNode* NextSibling() { return next; }
+
+ /// Navigate to a sibling node with the given 'value'.
+ const TiXmlNode* NextSibling( const char * ) const;
+ TiXmlNode* NextSibling( const char* _next ) {
+ return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) );
+ }
+
+ /** Convenience function to get through elements.
+ Calls NextSibling and ToElement. Will skip all non-Element
+ nodes. Returns 0 if there is not another element.
+ */
+ const TiXmlElement* NextSiblingElement() const;
+ TiXmlElement* NextSiblingElement() {
+ return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() );
+ }
+
+ /** Convenience function to get through elements.
+ Calls NextSibling and ToElement. Will skip all non-Element
+ nodes. Returns 0 if there is not another element.
+ */
+ const TiXmlElement* NextSiblingElement( const char * ) const;
+ TiXmlElement* NextSiblingElement( const char *_next ) {
+ return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) );
+ }
+
+ #ifdef TIXML_USE_STL
+ const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form.
+ TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form.
+ #endif
+
+ /// Convenience function to get through elements.
+ const TiXmlElement* FirstChildElement() const;
+ TiXmlElement* FirstChildElement() {
+ return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() );
+ }
+
+ /// Convenience function to get through elements.
+ const TiXmlElement* FirstChildElement( const char * _value ) const;
+ TiXmlElement* FirstChildElement( const char * _value ) {
+ return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) );
+ }
+
+ #ifdef TIXML_USE_STL
+ const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form.
+ TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form.
+ #endif
+
+ /** Query the type (as an enumerated value, above) of this node.
+ The possible types are: DOCUMENT, ELEMENT, COMMENT,
+ UNKNOWN, TEXT, and DECLARATION.
+ */
+ int Type() const { return type; }
+
+ /** Return a pointer to the Document this node lives in.
+ Returns null if not in a document.
+ */
+ const TiXmlDocument* GetDocument() const;
+ TiXmlDocument* GetDocument() {
+ return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() );
+ }
+
+ /// Returns true if this node has no children.
+ bool NoChildren() const { return !firstChild; }
+
+ virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+
+ virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+ virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+
+ /** Create an exact duplicate of this node and return it. The memory must be deleted
+ by the caller.
+ */
+ virtual TiXmlNode* Clone() const = 0;
+
+ /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
+ XML tree will be conditionally visited and the host will be called back
+ via the TiXmlVisitor interface.
+
+ This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
+ the XML for the callbacks, so the performance of TinyXML is unchanged by using this
+ interface versus any other.)
+
+ The interface has been based on ideas from:
+
+ - http://www.saxproject.org/
+ - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
+
+ Which are both good references for "visiting".
+
+ An example of using Accept():
+ @verbatim
+ TiXmlPrinter printer;
+ tinyxmlDoc.Accept( &printer );
+ const char* xmlcstr = printer.CStr();
+ @endverbatim
+ */
+ virtual bool Accept( TiXmlVisitor* visitor ) const = 0;
+
+protected:
+ TiXmlNode( NodeType _type );
+
+ // Copy to the allocated object. Shared functionality between Clone, Copy constructor,
+ // and the assignment operator.
+ void CopyTo( TiXmlNode* target ) const;
+
+ #ifdef TIXML_USE_STL
+ // The real work of the input operator.
+ virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0;
+ #endif
+
+ // Figure out what is at *p, and parse it. Returns null if it is not an xml node.
+ TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
+
+ TiXmlNode* parent;
+ NodeType type;
+
+ TiXmlNode* firstChild;
+ TiXmlNode* lastChild;
+
+ TIXML_STRING value;
+
+ TiXmlNode* prev;
+ TiXmlNode* next;
+
+private:
+ TiXmlNode( const TiXmlNode& ); // not implemented.
+ void operator=( const TiXmlNode& base ); // not allowed.
+};
+
+
+/** An attribute is a name-value pair. Elements have an arbitrary
+ number of attributes, each with a unique name.
+
+ @note The attributes are not TiXmlNodes, since they are not
+ part of the tinyXML document object model. There are other
+ suggested ways to look at this problem.
+*/
+class TiXmlAttribute : public TiXmlBase
+{
+ friend class TiXmlAttributeSet;
+
+public:
+ /// Construct an empty attribute.
+ TiXmlAttribute() : TiXmlBase()
+ {
+ document = 0;
+ prev = next = 0;
+ }
+
+ #ifdef TIXML_USE_STL
+ /// std::string constructor.
+ TiXmlAttribute( const std::string& _name, const std::string& _value )
+ {
+ name = _name;
+ value = _value;
+ document = 0;
+ prev = next = 0;
+ }
+ #endif
+
+ /// Construct an attribute with a name and value.
+ TiXmlAttribute( const char * _name, const char * _value )
+ {
+ name = _name;
+ value = _value;
+ document = 0;
+ prev = next = 0;
+ }
+
+ const char* Name() const { return name.c_str(); } ///< Return the name of this attribute.
+ const char* Value() const { return value.c_str(); } ///< Return the value of this attribute.
+ #ifdef TIXML_USE_STL
+ const std::string& ValueStr() const { return value; } ///< Return the value of this attribute.
+ #endif
+ int IntValue() const; ///< Return the value of this attribute, converted to an integer.
+ double DoubleValue() const; ///< Return the value of this attribute, converted to a double.
+
+ // Get the tinyxml string representation
+ const TIXML_STRING& NameTStr() const { return name; }
+
+ /** QueryIntValue examines the value string. It is an alternative to the
+ IntValue() method with richer error checking.
+ If the value is an integer, it is stored in 'value' and
+ the call returns TIXML_SUCCESS. If it is not
+ an integer, it returns TIXML_WRONG_TYPE.
+
+ A specialized but useful call. Note that for success it returns 0,
+ which is the opposite of almost all other TinyXml calls.
+ */
+ int QueryIntValue( int* _value ) const;
+ /// QueryDoubleValue examines the value string. See QueryIntValue().
+ int QueryDoubleValue( double* _value ) const;
+
+ void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute.
+ void SetValue( const char* _value ) { value = _value; } ///< Set the value.
+
+ void SetIntValue( int _value ); ///< Set the value from an integer.
+ void SetDoubleValue( double _value ); ///< Set the value from a double.
+
+ #ifdef TIXML_USE_STL
+ /// STL std::string form.
+ void SetName( const std::string& _name ) { name = _name; }
+ /// STL std::string form.
+ void SetValue( const std::string& _value ) { value = _value; }
+ #endif
+
+ /// Get the next sibling attribute in the DOM. Returns null at end.
+ const TiXmlAttribute* Next() const;
+ TiXmlAttribute* Next() {
+ return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() );
+ }
+
+ /// Get the previous sibling attribute in the DOM. Returns null at beginning.
+ const TiXmlAttribute* Previous() const;
+ TiXmlAttribute* Previous() {
+ return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() );
+ }
+
+ bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; }
+ bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; }
+ bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; }
+
+ /* Attribute parsing starts: first letter of the name
+ returns: the next char after the value end quote
+ */
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ // Prints this Attribute to a FILE stream.
+ virtual void Print( FILE* cfile, int depth ) const {
+ Print( cfile, depth, 0 );
+ }
+ void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
+
+ // [internal use]
+ // Set the document pointer so the attribute can report errors.
+ void SetDocument( TiXmlDocument* doc ) { document = doc; }
+
+private:
+ TiXmlAttribute( const TiXmlAttribute& ); // not implemented.
+ void operator=( const TiXmlAttribute& base ); // not allowed.
+
+ TiXmlDocument* document; // A pointer back to a document, for error reporting.
+ TIXML_STRING name;
+ TIXML_STRING value;
+ TiXmlAttribute* prev;
+ TiXmlAttribute* next;
+};
+
+
+/* A class used to manage a group of attributes.
+ It is only used internally, both by the ELEMENT and the DECLARATION.
+
+ The set can be changed transparent to the Element and Declaration
+ classes that use it, but NOT transparent to the Attribute
+ which has to implement a next() and previous() method. Which makes
+ it a bit problematic and prevents the use of STL.
+
+ This version is implemented with circular lists because:
+ - I like circular lists
+ - it demonstrates some independence from the (typical) doubly linked list.
+*/
+class TiXmlAttributeSet
+{
+public:
+ TiXmlAttributeSet();
+ ~TiXmlAttributeSet();
+
+ void Add( TiXmlAttribute* attribute );
+ void Remove( TiXmlAttribute* attribute );
+
+ const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
+ TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
+ const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
+ TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
+
+ const TiXmlAttribute* Find( const char* _name ) const;
+ TiXmlAttribute* Find( const char* _name ) {
+ return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) );
+ }
+ #ifdef TIXML_USE_STL
+ const TiXmlAttribute* Find( const std::string& _name ) const;
+ TiXmlAttribute* Find( const std::string& _name ) {
+ return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) );
+ }
+
+ #endif
+
+private:
+ //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element),
+ //*ME: this class must be also use a hidden/disabled copy-constructor !!!
+ TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed
+ void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute)
+
+ TiXmlAttribute sentinel;
+};
+
+
+/** The element is a container class. It has a value, the element name,
+ and can contain other elements, text, comments, and unknowns.
+ Elements also contain an arbitrary number of attributes.
+*/
+class TiXmlElement : public TiXmlNode
+{
+public:
+ /// Construct an element.
+ TiXmlElement (const char * in_value);
+
+ #ifdef TIXML_USE_STL
+ /// std::string constructor.
+ TiXmlElement( const std::string& _value );
+ #endif
+
+ TiXmlElement( const TiXmlElement& );
+
+ void operator=( const TiXmlElement& base );
+
+ virtual ~TiXmlElement();
+
+ /** Given an attribute name, Attribute() returns the value
+ for the attribute of that name, or null if none exists.
+ */
+ const char* Attribute( const char* name ) const;
+
+ /** Given an attribute name, Attribute() returns the value
+ for the attribute of that name, or null if none exists.
+ If the attribute exists and can be converted to an integer,
+ the integer value will be put in the return 'i', if 'i'
+ is non-null.
+ */
+ const char* Attribute( const char* name, int* i ) const;
+
+ /** Given an attribute name, Attribute() returns the value
+ for the attribute of that name, or null if none exists.
+ If the attribute exists and can be converted to an double,
+ the double value will be put in the return 'd', if 'd'
+ is non-null.
+ */
+ const char* Attribute( const char* name, double* d ) const;
+
+ /** QueryIntAttribute examines the attribute - it is an alternative to the
+ Attribute() method with richer error checking.
+ If the attribute is an integer, it is stored in 'value' and
+ the call returns TIXML_SUCCESS. If it is not
+ an integer, it returns TIXML_WRONG_TYPE. If the attribute
+ does not exist, then TIXML_NO_ATTRIBUTE is returned.
+ */
+ int QueryIntAttribute( const char* name, int* _value ) const;
+ /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute().
+ int QueryDoubleAttribute( const char* name, double* _value ) const;
+ /// QueryFloatAttribute examines the attribute - see QueryIntAttribute().
+ int QueryFloatAttribute( const char* name, float* _value ) const {
+ double d;
+ int result = QueryDoubleAttribute( name, &d );
+ if ( result == TIXML_SUCCESS ) {
+ *_value = (float)d;
+ }
+ return result;
+ }
+
+ #ifdef TIXML_USE_STL
+ /** Template form of the attribute query which will try to read the
+ attribute into the specified type. Very easy, very powerful, but
+ be careful to make sure to call this with the correct type.
+
+ NOTE: This method doesn't work correctly for 'string' types.
+
+ @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE
+ */
+ template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const
+ {
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+
+ std::stringstream sstream( node->ValueStr() );
+ sstream >> *outValue;
+ if ( !sstream.fail() )
+ return TIXML_SUCCESS;
+ return TIXML_WRONG_TYPE;
+ }
+ /*
+ This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string"
+ but template specialization is hard to get working cross-compiler. Leaving the bug for now.
+
+ // The above will fail for std::string because the space character is used as a seperator.
+ // Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string
+ template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const
+ {
+ const TiXmlAttribute* node = attributeSet.Find( name );
+ if ( !node )
+ return TIXML_NO_ATTRIBUTE;
+ *outValue = node->ValueStr();
+ return TIXML_SUCCESS;
+ }
+ */
+ #endif
+
+ /** Sets an attribute of name to a given value. The attribute
+ will be created if it does not exist, or changed if it does.
+ */
+ void SetAttribute( const char* name, const char * _value );
+
+ #ifdef TIXML_USE_STL
+ const std::string* Attribute( const std::string& name ) const;
+ const std::string* Attribute( const std::string& name, int* i ) const;
+ const std::string* Attribute( const std::string& name, double* d ) const;
+ int QueryIntAttribute( const std::string& name, int* _value ) const;
+ int QueryDoubleAttribute( const std::string& name, double* _value ) const;
+
+ /// STL std::string form.
+ void SetAttribute( const std::string& name, const std::string& _value );
+ ///< STL std::string form.
+ void SetAttribute( const std::string& name, int _value );
+ #endif
+
+ /** Sets an attribute of name to a given value. The attribute
+ will be created if it does not exist, or changed if it does.
+ */
+ void SetAttribute( const char * name, int value );
+
+ /** Sets an attribute of name to a given value. The attribute
+ will be created if it does not exist, or changed if it does.
+ */
+ void SetDoubleAttribute( const char * name, double value );
+
+ /** Deletes an attribute with the given name.
+ */
+ void RemoveAttribute( const char * name );
+ #ifdef TIXML_USE_STL
+ void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form.
+ #endif
+
+ const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element.
+ TiXmlAttribute* FirstAttribute() { return attributeSet.First(); }
+ const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element.
+ TiXmlAttribute* LastAttribute() { return attributeSet.Last(); }
+
+ /** Convenience function for easy access to the text inside an element. Although easy
+ and concise, GetText() is limited compared to getting the TiXmlText child
+ and accessing it directly.
+
+ If the first child of 'this' is a TiXmlText, the GetText()
+ returns the character string of the Text node, else null is returned.
+
+ This is a convenient method for getting the text of simple contained text:
+ @verbatim
+ <foo>This is text</foo>
+ const char* str = fooElement->GetText();
+ @endverbatim
+
+ 'str' will be a pointer to "This is text".
+
+ Note that this function can be misleading. If the element foo was created from
+ this XML:
+ @verbatim
+ <foo><b>This is text</b></foo>
+ @endverbatim
+
+ then the value of str would be null. The first child node isn't a text node, it is
+ another element. From this XML:
+ @verbatim
+ <foo>This is <b>text</b></foo>
+ @endverbatim
+ GetText() will return "This is ".
+
+ WARNING: GetText() accesses a child node - don't become confused with the
+ similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are
+ safe type casts on the referenced node.
+ */
+ const char* GetText() const;
+
+ /// Creates a new Element and returns it - the returned element is a copy.
+ virtual TiXmlNode* Clone() const;
+ // Print the Element to a FILE stream.
+ virtual void Print( FILE* cfile, int depth ) const;
+
+ /* Attribtue parsing starts: next char past '<'
+ returns: next char past '>'
+ */
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+
+ void CopyTo( TiXmlElement* target ) const;
+ void ClearThis(); // like clear, but initializes 'this' object as well
+
+ // Used to be public [internal use]
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+ /* [internal use]
+ Reads the "value" of the element -- another element, or text.
+ This should terminate with the current end tag.
+ */
+ const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );
+
+private:
+
+ TiXmlAttributeSet attributeSet;
+};
+
+
+/** An XML comment.
+*/
+class TiXmlComment : public TiXmlNode
+{
+public:
+ /// Constructs an empty comment.
+ TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {}
+ /// Construct a comment from text.
+ TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) {
+ SetValue( _value );
+ }
+ TiXmlComment( const TiXmlComment& );
+ void operator=( const TiXmlComment& base );
+
+ virtual ~TiXmlComment() {}
+
+ /// Returns a copy of this Comment.
+ virtual TiXmlNode* Clone() const;
+ // Write this Comment to a FILE stream.
+ virtual void Print( FILE* cfile, int depth ) const;
+
+ /* Attribtue parsing starts: at the ! of the !--
+ returns: next char past '>'
+ */
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+ void CopyTo( TiXmlComment* target ) const;
+
+ // used to be public
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+// virtual void StreamOut( TIXML_OSTREAM * out ) const;
+
+private:
+
+};
+
+
+/** XML text. A text node can have 2 ways to output the next. "normal" output
+ and CDATA. It will default to the mode it was parsed from the XML file and
+ you generally want to leave it alone, but you can change the output mode with
+ SetCDATA() and query it with CDATA().
+*/
+class TiXmlText : public TiXmlNode
+{
+ friend class TiXmlElement;
+public:
+ /** Constructor for text element. By default, it is treated as
+ normal, encoded text. If you want it be output as a CDATA text
+ element, set the parameter _cdata to 'true'
+ */
+ TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT)
+ {
+ SetValue( initValue );
+ cdata = false;
+ }
+ virtual ~TiXmlText() {}
+
+ #ifdef TIXML_USE_STL
+ /// Constructor.
+ TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT)
+ {
+ SetValue( initValue );
+ cdata = false;
+ }
+ #endif
+
+ TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); }
+ void operator=( const TiXmlText& base ) { base.CopyTo( this ); }
+
+ // Write this text object to a FILE stream.
+ virtual void Print( FILE* cfile, int depth ) const;
+
+ /// Queries whether this represents text using a CDATA section.
+ bool CDATA() const { return cdata; }
+ /// Turns on or off a CDATA representation of text.
+ void SetCDATA( bool _cdata ) { cdata = _cdata; }
+
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected :
+ /// [internal use] Creates a new Element and returns it.
+ virtual TiXmlNode* Clone() const;
+ void CopyTo( TiXmlText* target ) const;
+
+ bool Blank() const; // returns true if all white space and new lines
+ // [internal use]
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+
+private:
+ bool cdata; // true if this should be input and output as a CDATA style text element
+};
+
+
+/** In correct XML the declaration is the first entry in the file.
+ @verbatim
+ <?xml version="1.0" standalone="yes"?>
+ @endverbatim
+
+ TinyXml will happily read or write files without a declaration,
+ however. There are 3 possible attributes to the declaration:
+ version, encoding, and standalone.
+
+ Note: In this version of the code, the attributes are
+ handled as special cases, not generic attributes, simply
+ because there can only be at most 3 and they are always the same.
+*/
+class TiXmlDeclaration : public TiXmlNode
+{
+public:
+ /// Construct an empty declaration.
+ TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {}
+
+#ifdef TIXML_USE_STL
+ /// Constructor.
+ TiXmlDeclaration( const std::string& _version,
+ const std::string& _encoding,
+ const std::string& _standalone );
+#endif
+
+ /// Construct.
+ TiXmlDeclaration( const char* _version,
+ const char* _encoding,
+ const char* _standalone );
+
+ TiXmlDeclaration( const TiXmlDeclaration& copy );
+ void operator=( const TiXmlDeclaration& copy );
+
+ virtual ~TiXmlDeclaration() {}
+
+ /// Version. Will return an empty string if none was found.
+ const char *Version() const { return version.c_str (); }
+ /// Encoding. Will return an empty string if none was found.
+ const char *Encoding() const { return encoding.c_str (); }
+ /// Is this a standalone document?
+ const char *Standalone() const { return standalone.c_str (); }
+
+ /// Creates a copy of this Declaration and returns it.
+ virtual TiXmlNode* Clone() const;
+ // Print this declaration to a FILE stream.
+ virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
+ virtual void Print( FILE* cfile, int depth ) const {
+ Print( cfile, depth, 0 );
+ }
+
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+ void CopyTo( TiXmlDeclaration* target ) const;
+ // used to be public
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+
+private:
+
+ TIXML_STRING version;
+ TIXML_STRING encoding;
+ TIXML_STRING standalone;
+};
+
+
+/** Any tag that tinyXml doesn't recognize is saved as an
+ unknown. It is a tag of text, but should not be modified.
+ It will be written back to the XML, unchanged, when the file
+ is saved.
+
+ DTD tags get thrown into TiXmlUnknowns.
+*/
+class TiXmlUnknown : public TiXmlNode
+{
+public:
+ TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {}
+ virtual ~TiXmlUnknown() {}
+
+ TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); }
+ void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); }
+
+ /// Creates a copy of this Unknown and returns it.
+ virtual TiXmlNode* Clone() const;
+ // Print this Unknown to a FILE stream.
+ virtual void Print( FILE* cfile, int depth ) const;
+
+ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+ virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected:
+ void CopyTo( TiXmlUnknown* target ) const;
+
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+
+private:
+
+};
+
+
+/** Always the top level node. A document binds together all the
+ XML pieces. It can be saved, loaded, and printed to the screen.
+ The 'value' of a document node is the xml file name.
+*/
+class TiXmlDocument : public TiXmlNode
+{
+public:
+ /// Create an empty document, that has no name.
+ TiXmlDocument();
+ /// Create a document with a name. The name of the document is also the filename of the xml.
+ TiXmlDocument( const char * documentName );
+
+ #ifdef TIXML_USE_STL
+ /// Constructor.
+ TiXmlDocument( const std::string& documentName );
+ #endif
+
+ TiXmlDocument( const TiXmlDocument& copy );
+ void operator=( const TiXmlDocument& copy );
+
+ virtual ~TiXmlDocument() {}
+
+ /** Load a file using the current document value.
+ Returns true if successful. Will delete any existing
+ document data before loading.
+ */
+ bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+ /// Save a file using the current document value. Returns true if successful.
+ bool SaveFile() const;
+ /// Load a file using the given filename. Returns true if successful.
+ bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+ /// Save a file using the given filename. Returns true if successful.
+ bool SaveFile( const char * filename ) const;
+ /** Load a file using the given FILE*. Returns true if successful. Note that this method
+ doesn't stream - the entire object pointed at by the FILE*
+ will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
+ file location. Streaming may be added in the future.
+ */
+ bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+ /// Save a file using the given FILE*. Returns true if successful.
+ bool SaveFile( FILE* ) const;
+
+ #ifdef TIXML_USE_STL
+ bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version.
+ {
+// StringToBuffer f( filename );
+// return ( f.buffer && LoadFile( f.buffer, encoding ));
+ return LoadFile( filename.c_str(), encoding );
+ }
+ bool SaveFile( const std::string& filename ) const ///< STL std::string version.
+ {
+// StringToBuffer f( filename );
+// return ( f.buffer && SaveFile( f.buffer ));
+ return SaveFile( filename.c_str() );
+ }
+ #endif
+
+ /** Parse the given null terminated block of xml data. Passing in an encoding to this
+ method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml
+ to use that encoding, regardless of what TinyXml might otherwise try to detect.
+ */
+ virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+
+ /** Get the root element -- the only top level element -- of the document.
+ In well formed XML, there should only be one. TinyXml is tolerant of
+ multiple elements at the document level.
+ */
+ const TiXmlElement* RootElement() const { return FirstChildElement(); }
+ TiXmlElement* RootElement() { return FirstChildElement(); }
+
+ /** If an error occurs, Error will be set to true. Also,
+ - The ErrorId() will contain the integer identifier of the error (not generally useful)
+ - The ErrorDesc() method will return the name of the error. (very useful)
+ - The ErrorRow() and ErrorCol() will return the location of the error (if known)
+ */
+ bool Error() const { return error; }
+
+ /// Contains a textual (english) description of the error if one occurs.
+ const char * ErrorDesc() const { return errorDesc.c_str (); }
+
+ /** Generally, you probably want the error string ( ErrorDesc() ). But if you
+ prefer the ErrorId, this function will fetch it.
+ */
+ int ErrorId() const { return errorId; }
+
+ /** Returns the location (if known) of the error. The first column is column 1,
+ and the first row is row 1. A value of 0 means the row and column wasn't applicable
+ (memory errors, for example, have no row/column) or the parser lost the error. (An
+ error in the error reporting, in that case.)
+
+ @sa SetTabSize, Row, Column
+ */
+ int ErrorRow() const { return errorLocation.row+1; }
+ int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow()
+
+ /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol())
+ to report the correct values for row and column. It does not change the output
+ or input in any way.
+
+ By calling this method, with a tab size
+ greater than 0, the row and column of each node and attribute is stored
+ when the file is loaded. Very useful for tracking the DOM back in to
+ the source file.
+
+ The tab size is required for calculating the location of nodes. If not
+ set, the default of 4 is used. The tabsize is set per document. Setting
+ the tabsize to 0 disables row/column tracking.
+
+ Note that row and column tracking is not supported when using operator>>.
+
+ The tab size needs to be enabled before the parse or load. Correct usage:
+ @verbatim
+ TiXmlDocument doc;
+ doc.SetTabSize( 8 );
+ doc.Load( "myfile.xml" );
+ @endverbatim
+
+ @sa Row, Column
+ */
+ void SetTabSize( int _tabsize ) { tabsize = _tabsize; }
+
+ int TabSize() const { return tabsize; }
+
+ /** If you have handled the error, it can be reset with this call. The error
+ state is automatically cleared if you Parse a new XML block.
+ */
+ void ClearError() { error = false;
+ errorId = 0;
+ errorDesc = "";
+ errorLocation.row = errorLocation.col = 0;
+ //errorLocation.last = 0;
+ }
+
+ /** Write the document to standard out using formatted printing ("pretty print"). */
+ void Print() const { Print( stdout, 0 ); }
+
+ /* Write the document to a string using formatted printing ("pretty print"). This
+ will allocate a character array (new char[]) and return it as a pointer. The
+ calling code pust call delete[] on the return char* to avoid a memory leak.
+ */
+ //char* PrintToMemory() const;
+
+ /// Print this Document to a FILE stream.
+ virtual void Print( FILE* cfile, int depth = 0 ) const;
+ // [internal use]
+ void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding );
+
+ virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+ virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+ /** Walk the XML tree visiting this node and all of its children.
+ */
+ virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected :
+ // [internal use]
+ virtual TiXmlNode* Clone() const;
+ #ifdef TIXML_USE_STL
+ virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+ #endif
+
+private:
+ void CopyTo( TiXmlDocument* target ) const;
+
+ bool error;
+ int errorId;
+ TIXML_STRING errorDesc;
+ int tabsize;
+ TiXmlCursor errorLocation;
+ bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write.
+};
+
+
+/**
+ A TiXmlHandle is a class that wraps a node pointer with null checks; this is
+ an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml
+ DOM structure. It is a separate utility class.
+
+ Take an example:
+ @verbatim
+ <Document>
+ <Element attributeA = "valueA">
+ <Child attributeB = "value1" />
+ <Child attributeB = "value2" />
+ </Element>
+ <Document>
+ @endverbatim
+
+ Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
+ easy to write a *lot* of code that looks like:
+
+ @verbatim
+ TiXmlElement* root = document.FirstChildElement( "Document" );
+ if ( root )
+ {
+ TiXmlElement* element = root->FirstChildElement( "Element" );
+ if ( element )
+ {
+ TiXmlElement* child = element->FirstChildElement( "Child" );
+ if ( child )
+ {
+ TiXmlElement* child2 = child->NextSiblingElement( "Child" );
+ if ( child2 )
+ {
+ // Finally do something useful.
+ @endverbatim
+
+ And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity
+ of such code. A TiXmlHandle checks for null pointers so it is perfectly safe
+ and correct to use:
+
+ @verbatim
+ TiXmlHandle docHandle( &document );
+ TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement();
+ if ( child2 )
+ {
+ // do something useful
+ @endverbatim
+
+ Which is MUCH more concise and useful.
+
+ It is also safe to copy handles - internally they are nothing more than node pointers.
+ @verbatim
+ TiXmlHandle handleCopy = handle;
+ @endverbatim
+
+ What they should not be used for is iteration:
+
+ @verbatim
+ int i=0;
+ while ( true )
+ {
+ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement();
+ if ( !child )
+ break;
+ // do something
+ ++i;
+ }
+ @endverbatim
+
+ It seems reasonable, but it is in fact two embedded while loops. The Child method is
+ a linear walk to find the element, so this code would iterate much more than it needs
+ to. Instead, prefer:
+
+ @verbatim
+ TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement();
+
+ for( child; child; child=child->NextSiblingElement() )
+ {
+ // do something
+ }
+ @endverbatim
+*/
+class TiXmlHandle
+{
+public:
+ /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
+ TiXmlHandle( TiXmlNode* _node ) { this->node = _node; }
+ /// Copy constructor
+ TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; }
+ TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; }
+
+ /// Return a handle to the first child node.
+ TiXmlHandle FirstChild() const;
+ /// Return a handle to the first child node with the given name.
+ TiXmlHandle FirstChild( const char * value ) const;
+ /// Return a handle to the first child element.
+ TiXmlHandle FirstChildElement() const;
+ /// Return a handle to the first child element with the given name.
+ TiXmlHandle FirstChildElement( const char * value ) const;
+
+ /** Return a handle to the "index" child with the given name.
+ The first child is 0, the second 1, etc.
+ */
+ TiXmlHandle Child( const char* value, int index ) const;
+ /** Return a handle to the "index" child.
+ The first child is 0, the second 1, etc.
+ */
+ TiXmlHandle Child( int index ) const;
+ /** Return a handle to the "index" child element with the given name.
+ The first child element is 0, the second 1, etc. Note that only TiXmlElements
+ are indexed: other types are not counted.
+ */
+ TiXmlHandle ChildElement( const char* value, int index ) const;
+ /** Return a handle to the "index" child element.
+ The first child element is 0, the second 1, etc. Note that only TiXmlElements
+ are indexed: other types are not counted.
+ */
+ TiXmlHandle ChildElement( int index ) const;
+
+ #ifdef TIXML_USE_STL
+ TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); }
+ TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); }
+
+ TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); }
+ TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); }
+ #endif
+
+ /** Return the handle as a TiXmlNode. This may return null.
+ */
+ TiXmlNode* ToNode() const { return node; }
+ /** Return the handle as a TiXmlElement. This may return null.
+ */
+ TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+ /** Return the handle as a TiXmlText. This may return null.
+ */
+ TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+ /** Return the handle as a TiXmlUnknown. This may return null.
+ */
+ TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+
+ /** @deprecated use ToNode.
+ Return the handle as a TiXmlNode. This may return null.
+ */
+ TiXmlNode* Node() const { return ToNode(); }
+ /** @deprecated use ToElement.
+ Return the handle as a TiXmlElement. This may return null.
+ */
+ TiXmlElement* Element() const { return ToElement(); }
+ /** @deprecated use ToText()
+ Return the handle as a TiXmlText. This may return null.
+ */
+ TiXmlText* Text() const { return ToText(); }
+ /** @deprecated use ToUnknown()
+ Return the handle as a TiXmlUnknown. This may return null.
+ */
+ TiXmlUnknown* Unknown() const { return ToUnknown(); }
+
+private:
+ TiXmlNode* node;
+};
+
+
+/** Print to memory functionality. The TiXmlPrinter is useful when you need to:
+
+ -# Print to memory (especially in non-STL mode)
+ -# Control formatting (line endings, etc.)
+
+ When constructed, the TiXmlPrinter is in its default "pretty printing" mode.
+ Before calling Accept() you can call methods to control the printing
+ of the XML document. After TiXmlNode::Accept() is called, the printed document can
+ be accessed via the CStr(), Str(), and Size() methods.
+
+ TiXmlPrinter uses the Visitor API.
+ @verbatim
+ TiXmlPrinter printer;
+ printer.SetIndent( "\t" );
+
+ doc.Accept( &printer );
+ fprintf( stdout, "%s", printer.CStr() );
+ @endverbatim
+*/
+class TiXmlPrinter : public TiXmlVisitor
+{
+public:
+ TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ),
+ buffer(), indent( " " ), lineBreak( "\n" ) {}
+
+ virtual bool VisitEnter( const TiXmlDocument& doc );
+ virtual bool VisitExit( const TiXmlDocument& doc );
+
+ virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute );
+ virtual bool VisitExit( const TiXmlElement& element );
+
+ virtual bool Visit( const TiXmlDeclaration& declaration );
+ virtual bool Visit( const TiXmlText& text );
+ virtual bool Visit( const TiXmlComment& comment );
+ virtual bool Visit( const TiXmlUnknown& unknown );
+
+ /** Set the indent characters for printing. By default 4 spaces
+ but tab (\t) is also useful, or null/empty string for no indentation.
+ */
+ void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; }
+ /// Query the indention string.
+ const char* Indent() { return indent.c_str(); }
+ /** Set the line breaking string. By default set to newline (\n).
+ Some operating systems prefer other characters, or can be
+ set to the null/empty string for no indenation.
+ */
+ void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; }
+ /// Query the current line breaking string.
+ const char* LineBreak() { return lineBreak.c_str(); }
+
+ /** Switch over to "stream printing" which is the most dense formatting without
+ linebreaks. Common when the XML is needed for network transmission.
+ */
+ void SetStreamPrinting() { indent = "";
+ lineBreak = "";
+ }
+ /// Return the result.
+ const char* CStr() { return buffer.c_str(); }
+ /// Return the length of the result string.
+ size_t Size() { return buffer.size(); }
+
+ #ifdef TIXML_USE_STL
+ /// Return the result.
+ const std::string& Str() { return buffer; }
+ #endif
+
+private:
+ void DoIndent() {
+ for( int i=0; i<depth; ++i )
+ buffer += indent;
+ }
+ void DoLineBreak() {
+ buffer += lineBreak;
+ }
+
+ int depth;
+ bool simpleTextPrint;
+ TIXML_STRING buffer;
+ TIXML_STRING indent;
+ TIXML_STRING lineBreak;
+};
+
+
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+#endif
+
diff --git a/library/tinyxml/tinyxmlerror.cpp b/library/tinyxml/tinyxmlerror.cpp
new file mode 100644
index 00000000..d24f63b2
--- /dev/null
+++ b/library/tinyxml/tinyxmlerror.cpp
@@ -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.",
+};
diff --git a/library/tinyxml/tinyxmlparser.cpp b/library/tinyxml/tinyxmlparser.cpp
new file mode 100644
index 00000000..9c91b4f9
--- /dev/null
+++ b/library/tinyxml/tinyxmlparser.cpp
@@ -0,0 +1,1638 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code (2.0 and earlier )copyright (c) 2000-2002 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 <ctype.h>
+#include <stddef.h>
+
+#include "tinyxml.h"
+
+//#define DEBUG_PARSER
+#if defined( DEBUG_PARSER )
+# if defined( DEBUG ) && defined( _MSC_VER )
+# include <windows.h>
+# define TIXML_LOG OutputDebugString
+# else
+# define TIXML_LOG printf
+# endif
+#endif
+
+// Note tha "PutString" hardcodes the same list. This
+// is less flexible than it appears. Changing the entries
+// or order will break putstring.
+TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] =
+{
+ { "&amp;", 5, '&' },
+ { "&lt;", 4, '<' },
+ { "&gt;", 4, '>' },
+ { "&quot;", 6, '\"' },
+ { "&apos;", 6, '\'' }
+};
+
+// Bunch of unicode info at:
+// http://www.unicode.org/faq/utf_bom.html
+// Including the basic of this table, which determines the #bytes in the
+// sequence from the lead byte. 1 placed for invalid sequences --
+// although the result will be junk, pass it through as much as possible.
+// Beware of the non-characters in UTF-8:
+// ef bb bf (Microsoft "lead bytes")
+// ef bf be
+// ef bf bf
+
+const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+const int TiXmlBase::utf8ByteTable[256] =
+{
+ // 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte
+ 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
+};
+
+
+void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
+{
+ const unsigned long BYTE_MASK = 0xBF;
+ const unsigned long BYTE_MARK = 0x80;
+ const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+ if (input < 0x80)
+ *length = 1;
+ else if ( input < 0x800 )
+ *length = 2;
+ else if ( input < 0x10000 )
+ *length = 3;
+ else if ( input < 0x200000 )
+ *length = 4;
+ else
+ { *length = 0; return; } // This code won't covert this correctly anyway.
+
+ output += *length;
+
+ // Scary scary fall throughs.
+ switch (*length)
+ {
+ case 4:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ case 3:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ case 2:
+ --output;
+ *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+ input >>= 6;
+ case 1:
+ --output;
+ *output = (char)(input | FIRST_BYTE_MARK[*length]);
+ }
+}
+
+
+/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
+{
+ // This will only work for low-ascii, everything else is assumed to be a valid
+ // letter. I'm not sure this is the best approach, but it is quite tricky trying
+ // to figure out alhabetical vs. not across encoding. So take a very
+ // conservative approach.
+
+// if ( encoding == TIXML_ENCODING_UTF8 )
+// {
+ if ( anyByte < 127 )
+ return isalpha( anyByte );
+ else
+ return 1; // What else to do? The unicode set is huge...get the english ones right.
+// }
+// else
+// {
+// return isalpha( anyByte );
+// }
+}
+
+
+/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
+{
+ // This will only work for low-ascii, everything else is assumed to be a valid
+ // letter. I'm not sure this is the best approach, but it is quite tricky trying
+ // to figure out alhabetical vs. not across encoding. So take a very
+ // conservative approach.
+
+// if ( encoding == TIXML_ENCODING_UTF8 )
+// {
+ if ( anyByte < 127 )
+ return isalnum( anyByte );
+ else
+ return 1; // What else to do? The unicode set is huge...get the english ones right.
+// }
+// else
+// {
+// return isalnum( anyByte );
+// }
+}
+
+
+class TiXmlParsingData
+{
+ friend class TiXmlDocument;
+ public:
+ void Stamp( const char* now, TiXmlEncoding encoding );
+
+ const TiXmlCursor& Cursor() { return cursor; }
+
+ private:
+ // Only used by the document!
+ TiXmlParsingData( const char* start, int _tabsize, int row, int col )
+ {
+ assert( start );
+ stamp = start;
+ tabsize = _tabsize;
+ cursor.row = row;
+ cursor.col = col;
+ }
+
+ TiXmlCursor cursor;
+ const char* stamp;
+ int tabsize;
+};
+
+
+void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )
+{
+ assert( now );
+
+ // Do nothing if the tabsize is 0.
+ if ( tabsize < 1 )
+ {
+ return;
+ }
+
+ // Get the current row, column.
+ int row = cursor.row;
+ int col = cursor.col;
+ const char* p = stamp;
+ assert( p );
+
+ while ( p < now )
+ {
+ // Treat p as unsigned, so we have a happy compiler.
+ const unsigned char* pU = (const unsigned char*)p;
+
+ // Code contributed by Fletcher Dunn: (modified by lee)
+ switch (*pU) {
+ case 0:
+ // We *should* never get here, but in case we do, don't
+ // advance past the terminating null character, ever
+ return;
+
+ case '\r':
+ // bump down to the next line
+ ++row;
+ col = 0;
+ // Eat the character
+ ++p;
+
+ // Check for \r\n sequence, and treat this as a single character
+ if (*p == '\n') {
+ ++p;
+ }
+ break;
+
+ case '\n':
+ // bump down to the next line
+ ++row;
+ col = 0;
+
+ // Eat the character
+ ++p;
+
+ // Check for \n\r sequence, and treat this as a single
+ // character. (Yes, this bizarre thing does occur still
+ // on some arcane platforms...)
+ if (*p == '\r') {
+ ++p;
+ }
+ break;
+
+ case '\t':
+ // Eat the character
+ ++p;
+
+ // Skip to next tab stop
+ col = (col / tabsize + 1) * tabsize;
+ break;
+
+ case TIXML_UTF_LEAD_0:
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ if ( *(p+1) && *(p+2) )
+ {
+ // In these cases, don't advance the column. These are
+ // 0-width spaces.
+ if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )
+ p += 3;
+ else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )
+ p += 3;
+ else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )
+ p += 3;
+ else
+ { p +=3; ++col; } // A normal character.
+ }
+ }
+ else
+ {
+ ++p;
+ ++col;
+ }
+ break;
+
+ default:
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ // Eat the 1 to 4 byte utf8 character.
+ int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)];
+ if ( step == 0 )
+ step = 1; // Error case from bad encoding, but handle gracefully.
+ p += step;
+
+ // Just advance one column, of course.
+ ++col;
+ }
+ else
+ {
+ ++p;
+ ++col;
+ }
+ break;
+ }
+ }
+ cursor.row = row;
+ cursor.col = col;
+ assert( cursor.row >= -1 );
+ assert( cursor.col >= -1 );
+ stamp = p;
+ assert( stamp );
+}
+
+
+const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )
+{
+ if ( !p || !*p )
+ {
+ return 0;
+ }
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ while ( *p )
+ {
+ const unsigned char* pU = (const unsigned char*)p;
+
+ // Skip the stupid Microsoft UTF-8 Byte order marks
+ if ( *(pU+0)==TIXML_UTF_LEAD_0
+ && *(pU+1)==TIXML_UTF_LEAD_1
+ && *(pU+2)==TIXML_UTF_LEAD_2 )
+ {
+ p += 3;
+ continue;
+ }
+ else if(*(pU+0)==TIXML_UTF_LEAD_0
+ && *(pU+1)==0xbfU
+ && *(pU+2)==0xbeU )
+ {
+ p += 3;
+ continue;
+ }
+ else if(*(pU+0)==TIXML_UTF_LEAD_0
+ && *(pU+1)==0xbfU
+ && *(pU+2)==0xbfU )
+ {
+ p += 3;
+ continue;
+ }
+
+ if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space.
+ ++p;
+ else
+ break;
+ }
+ }
+ else
+ {
+ while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' )
+ ++p;
+ }
+
+ return p;
+}
+
+#ifdef TIXML_USE_STL
+/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )
+{
+ for( ;; )
+ {
+ if ( !in->good() ) return false;
+
+ int c = in->peek();
+ // At this scope, we can't get to a document. So fail silently.
+ if ( !IsWhiteSpace( c ) || c <= 0 )
+ return true;
+
+ *tag += (char) in->get();
+ }
+}
+
+/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag )
+{
+ //assert( character > 0 && character < 128 ); // else it won't work in utf-8
+ while ( in->good() )
+ {
+ int c = in->peek();
+ if ( c == character )
+ return true;
+ if ( c <= 0 ) // Silent failure: can't get document at this scope
+ return false;
+
+ in->get();
+ *tag += (char) c;
+ }
+ return false;
+}
+#endif
+
+// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The
+// "assign" optimization removes over 10% of the execution time.
+//
+const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )
+{
+ // Oddly, not supported on some comilers,
+ //name->clear();
+ // So use this:
+ *name = "";
+ assert( p );
+
+ // Names start with letters or underscores.
+ // Of course, in unicode, tinyxml has no idea what a letter *is*. The
+ // algorithm is generous.
+ //
+ // After that, they can be letters, underscores, numbers,
+ // hyphens, or colons. (Colons are valid ony for namespaces,
+ // but tinyxml can't tell namespaces from names.)
+ if ( p && *p
+ && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )
+ {
+ const char* start = p;
+ while( p && *p
+ && ( IsAlphaNum( (unsigned char ) *p, encoding )
+ || *p == '_'
+ || *p == '-'
+ || *p == '.'
+ || *p == ':' ) )
+ {
+ //(*name) += *p; // expensive
+ ++p;
+ }
+ if ( p-start > 0 ) {
+ name->assign( start, p-start );
+ }
+ return p;
+ }
+ return 0;
+}
+
+const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )
+{
+ // Presume an entity, and pull it out.
+ TIXML_STRING ent;
+ int i;
+ *length = 0;
+
+ if ( *(p+1) && *(p+1) == '#' && *(p+2) )
+ {
+ unsigned long ucs = 0;
+ ptrdiff_t delta = 0;
+ unsigned mult = 1;
+
+ if ( *(p+2) == 'x' )
+ {
+ // Hexadecimal.
+ if ( !*(p+3) ) return 0;
+
+ const char* q = p+3;
+ q = strchr( q, ';' );
+
+ if ( !q || !*q ) return 0;
+
+ delta = q-p;
+ --q;
+
+ while ( *q != 'x' )
+ {
+ if ( *q >= '0' && *q <= '9' )
+ ucs += mult * (*q - '0');
+ else if ( *q >= 'a' && *q <= 'f' )
+ ucs += mult * (*q - 'a' + 10);
+ else if ( *q >= 'A' && *q <= 'F' )
+ ucs += mult * (*q - 'A' + 10 );
+ else
+ return 0;
+ mult *= 16;
+ --q;
+ }
+ }
+ else
+ {
+ // Decimal.
+ if ( !*(p+2) ) return 0;
+
+ const char* q = p+2;
+ q = strchr( q, ';' );
+
+ if ( !q || !*q ) return 0;
+
+ delta = q-p;
+ --q;
+
+ while ( *q != '#' )
+ {
+ if ( *q >= '0' && *q <= '9' )
+ ucs += mult * (*q - '0');
+ else
+ return 0;
+ mult *= 10;
+ --q;
+ }
+ }
+ if ( encoding == TIXML_ENCODING_UTF8 )
+ {
+ // convert the UCS to UTF-8
+ ConvertUTF32ToUTF8( ucs, value, length );
+ }
+ else
+ {
+ *value = (char)ucs;
+ *length = 1;
+ }
+ return p + delta + 1;
+ }
+
+ // Now try to match it.
+ for( i=0; i<NUM_ENTITY; ++i )
+ {
+ if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
+ {
+ assert( strlen( entity[i].str ) == entity[i].strLength );
+ *value = entity[i].chr;
+ *length = 1;
+ return ( p + entity[i].strLength );
+ }
+ }
+
+ // So it wasn't an entity, its unrecognized, or something like that.
+ *value = *p; // Don't put back the last one, since we return it!
+ //*length = 1; // Leave unrecognized entities - this doesn't really work.
+ // Just writes strange XML.
+ return p+1;
+}
+
+
+bool TiXmlBase::StringEqual( const char* p,
+ const char* tag,
+ bool ignoreCase,
+ TiXmlEncoding encoding )
+{
+ assert( p );
+ assert( tag );
+ if ( !p || !*p )
+ {
+ assert( 0 );
+ return false;
+ }
+
+ const char* q = p;
+
+ if ( ignoreCase )
+ {
+ while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )
+ {
+ ++q;
+ ++tag;
+ }
+
+ if ( *tag == 0 )
+ return true;
+ }
+ else
+ {
+ while ( *q && *tag && *q == *tag )
+ {
+ ++q;
+ ++tag;
+ }
+
+ if ( *tag == 0 ) // Have we found the end of the tag, and everything equal?
+ return true;
+ }
+ return false;
+}
+
+const char* TiXmlBase::ReadText( const char* p,
+ TIXML_STRING * text,
+ bool trimWhiteSpace,
+ const char* endTag,
+ bool caseInsensitive,
+ TiXmlEncoding encoding )
+{
+ *text = "";
+ if ( !trimWhiteSpace // certain tags always keep whitespace
+ || !condenseWhiteSpace ) // if true, whitespace is always kept
+ {
+ // Keep all the white space.
+ while ( p && *p
+ && !StringEqual( p, endTag, caseInsensitive, encoding )
+ )
+ {
+ int len;
+ char cArr[4] = { 0, 0, 0, 0 };
+ p = GetChar( p, cArr, &len, encoding );
+ text->append( cArr, len );
+ }
+ }
+ else
+ {
+ bool whitespace = false;
+
+ // Remove leading white space:
+ p = SkipWhiteSpace( p, encoding );
+ while ( p && *p
+ && !StringEqual( p, endTag, caseInsensitive, encoding ) )
+ {
+ if ( *p == '\r' || *p == '\n' )
+ {
+ whitespace = true;
+ ++p;
+ }
+ else if ( IsWhiteSpace( *p ) )
+ {
+ whitespace = true;
+ ++p;
+ }
+ else
+ {
+ // If we've found whitespace, add it before the
+ // new character. Any whitespace just becomes a space.
+ if ( whitespace )
+ {
+ (*text) += ' ';
+ whitespace = false;
+ }
+ int len;
+ char cArr[4] = { 0, 0, 0, 0 };
+ p = GetChar( p, cArr, &len, encoding );
+ if ( len == 1 )
+ (*text) += cArr[0]; // more efficient
+ else
+ text->append( cArr, len );
+ }
+ }
+ }
+ if ( p )
+ p += strlen( endTag );
+ return p;
+}
+
+#ifdef TIXML_USE_STL
+
+void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+ // The basic issue with a document is that we don't know what we're
+ // streaming. Read something presumed to be a tag (and hope), then
+ // identify it, and call the appropriate stream method on the tag.
+ //
+ // This "pre-streaming" will never read the closing ">" so the
+ // sub-tag can orient itself.
+
+ if ( !StreamTo( in, '<', tag ) )
+ {
+ SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+
+ while ( in->good() )
+ {
+ int tagIndex = (int) tag->length();
+ while ( in->good() && in->peek() != '>' )
+ {
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ break;
+ }
+ (*tag) += (char) c;
+ }
+
+ if ( in->good() )
+ {
+ // We now have something we presume to be a node of
+ // some sort. Identify it, and call the node to
+ // continue streaming.
+ TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );
+
+ if ( node )
+ {
+ node->StreamIn( in, tag );
+ bool isElement = node->ToElement() != 0;
+ delete node;
+ node = 0;
+
+ // If this is the root element, we're done. Parsing will be
+ // done by the >> operator.
+ if ( isElement )
+ {
+ return;
+ }
+ }
+ else
+ {
+ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+ }
+ }
+ // We should have returned sooner.
+ SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
+}
+
+#endif
+
+const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )
+{
+ ClearError();
+
+ // Parse away, at the document level. Since a document
+ // contains nothing but other tags, most of what happens
+ // here is skipping white space.
+ if ( !p || !*p )
+ {
+ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+
+ // Note that, for a document, this needs to come
+ // before the while space skip, so that parsing
+ // starts from the pointer we are given.
+ location.Clear();
+ if ( prevData )
+ {
+ location.row = prevData->cursor.row;
+ location.col = prevData->cursor.col;
+ }
+ else
+ {
+ location.row = 0;
+ location.col = 0;
+ }
+ TiXmlParsingData data( p, TabSize(), location.row, location.col );
+ location = data.Cursor();
+
+ if ( encoding == TIXML_ENCODING_UNKNOWN )
+ {
+ // Check for the Microsoft UTF-8 lead bytes.
+ const unsigned char* pU = (const unsigned char*)p;
+ if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
+ && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
+ && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
+ {
+ encoding = TIXML_ENCODING_UTF8;
+ useMicrosoftBOM = true;
+ }
+ }
+
+ p = SkipWhiteSpace( p, encoding );
+ if ( !p )
+ {
+ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return 0;
+ }
+
+ while ( p && *p )
+ {
+ TiXmlNode* node = Identify( p, encoding );
+ if ( node )
+ {
+ p = node->Parse( p, &data, encoding );
+ LinkEndChild( node );
+ }
+ else
+ {
+ break;
+ }
+
+ // Did we get encoding info?
+ if ( encoding == TIXML_ENCODING_UNKNOWN
+ && node->ToDeclaration() )
+ {
+ TiXmlDeclaration* dec = node->ToDeclaration();
+ const char* enc = dec->Encoding();
+ assert( enc );
+
+ if ( *enc == 0 )
+ encoding = TIXML_ENCODING_UTF8;
+ else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )
+ encoding = TIXML_ENCODING_UTF8;
+ else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )
+ encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice
+ else
+ encoding = TIXML_ENCODING_LEGACY;
+ }
+
+ p = SkipWhiteSpace( p, encoding );
+ }
+
+ // Was this empty?
+ if ( !firstChild ) {
+ SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
+ return 0;
+ }
+
+ // All is well.
+ return p;
+}
+
+void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ // The first error in a chain is more accurate - don't set again!
+ if ( error )
+ return;
+
+ assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
+ error = true;
+ errorId = err;
+ errorDesc = errorString[ errorId ];
+
+ errorLocation.Clear();
+ if ( pError && data )
+ {
+ data->Stamp( pError, encoding );
+ errorLocation = data->Cursor();
+ }
+}
+
+
+TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
+{
+ TiXmlNode* returnNode = 0;
+
+ p = SkipWhiteSpace( p, encoding );
+ if( !p || !*p || *p != '<' )
+ {
+ return 0;
+ }
+
+ TiXmlDocument* doc = GetDocument();
+ p = SkipWhiteSpace( p, encoding );
+
+ if ( !p || !*p )
+ {
+ return 0;
+ }
+
+ // What is this thing?
+ // - Elements start with a letter or underscore, but xml is reserved.
+ // - Comments: <!--
+ // - Decleration: <?xml
+ // - Everthing else is unknown to tinyxml.
+ //
+
+ const char* xmlHeader = { "<?xml" };
+ const char* commentHeader = { "<!--" };
+ const char* dtdHeader = { "<!" };
+ const char* cdataHeader = { "<![CDATA[" };
+
+ if ( StringEqual( p, xmlHeader, true, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Declaration\n" );
+ #endif
+ returnNode = new TiXmlDeclaration();
+ }
+ else if ( StringEqual( p, commentHeader, false, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Comment\n" );
+ #endif
+ returnNode = new TiXmlComment();
+ }
+ else if ( StringEqual( p, cdataHeader, false, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing CDATA\n" );
+ #endif
+ TiXmlText* text = new TiXmlText( "" );
+ text->SetCDATA( true );
+ returnNode = text;
+ }
+ else if ( StringEqual( p, dtdHeader, false, encoding ) )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Unknown(1)\n" );
+ #endif
+ returnNode = new TiXmlUnknown();
+ }
+ else if ( IsAlpha( *(p+1), encoding )
+ || *(p+1) == '_' )
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Element\n" );
+ #endif
+ returnNode = new TiXmlElement( "" );
+ }
+ else
+ {
+ #ifdef DEBUG_PARSER
+ TIXML_LOG( "XML parsing Unknown(2)\n" );
+ #endif
+ returnNode = new TiXmlUnknown();
+ }
+
+ if ( returnNode )
+ {
+ // Set the parent, so it can report errors
+ returnNode->parent = this;
+ }
+ else
+ {
+ if ( doc )
+ doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
+ }
+ return returnNode;
+}
+
+#ifdef TIXML_USE_STL
+
+void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)
+{
+ // We're called with some amount of pre-parsing. That is, some of "this"
+ // element is in "tag". Go ahead and stream to the closing ">"
+ while( in->good() )
+ {
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+ (*tag) += (char) c ;
+
+ if ( c == '>' )
+ break;
+ }
+
+ if ( tag->length() < 3 ) return;
+
+ // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
+ // If not, identify and stream.
+
+ if ( tag->at( tag->length() - 1 ) == '>'
+ && tag->at( tag->length() - 2 ) == '/' )
+ {
+ // All good!
+ return;
+ }
+ else if ( tag->at( tag->length() - 1 ) == '>' )
+ {
+ // There is more. Could be:
+ // text
+ // cdata text (which looks like another node)
+ // closing tag
+ // another node.
+ for ( ;; )
+ {
+ StreamWhiteSpace( in, tag );
+
+ // Do we have text?
+ if ( in->good() && in->peek() != '<' )
+ {
+ // Yep, text.
+ TiXmlText text( "" );
+ text.StreamIn( in, tag );
+
+ // What follows text is a closing tag or another node.
+ // Go around again and figure it out.
+ continue;
+ }
+
+ // We now have either a closing tag...or another node.
+ // We should be at a "<", regardless.
+ if ( !in->good() ) return;
+ assert( in->peek() == '<' );
+ int tagIndex = (int) tag->length();
+
+ bool closingTag = false;
+ bool firstCharFound = false;
+
+ for( ;; )
+ {
+ if ( !in->good() )
+ return;
+
+ int c = in->peek();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+
+ if ( c == '>' )
+ break;
+
+ *tag += (char) c;
+ in->get();
+
+ // Early out if we find the CDATA id.
+ if ( c == '[' && tag->size() >= 9 )
+ {
+ size_t len = tag->size();
+ const char* start = tag->c_str() + len - 9;
+ if ( strcmp( start, "<![CDATA[" ) == 0 ) {
+ assert( !closingTag );
+ break;
+ }
+ }
+
+ if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
+ {
+ firstCharFound = true;
+ if ( c == '/' )
+ closingTag = true;
+ }
+ }
+ // If it was a closing tag, then read in the closing '>' to clean up the input stream.
+ // If it was not, the streaming will be done by the tag.
+ if ( closingTag )
+ {
+ if ( !in->good() )
+ return;
+
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+ assert( c == '>' );
+ *tag += (char) c;
+
+ // We are done, once we've found our closing tag.
+ return;
+ }
+ else
+ {
+ // If not a closing tag, id it, and stream.
+ const char* tagloc = tag->c_str() + tagIndex;
+ TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
+ if ( !node )
+ return;
+ node->StreamIn( in, tag );
+ delete node;
+ node = 0;
+
+ // No return: go around from the beginning: text, closing tag, or node.
+ }
+ }
+ }
+}
+#endif
+
+const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ p = SkipWhiteSpace( p, encoding );
+ TiXmlDocument* document = GetDocument();
+
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
+ return 0;
+ }
+
+ if ( data )
+ {
+ data->Stamp( p, encoding );
+ location = data->Cursor();
+ }
+
+ if ( *p != '<' )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
+ return 0;
+ }
+
+ p = SkipWhiteSpace( p+1, encoding );
+
+ // Read the name.
+ const char* pErr = p;
+
+ p = ReadName( p, &value, encoding );
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
+ return 0;
+ }
+
+ TIXML_STRING endTag ("</");
+ endTag += value;
+ endTag += ">";
+
+ // Check for and read attributes. Also look for an empty
+ // tag or an end tag.
+ while ( p && *p )
+ {
+ pErr = p;
+ p = SkipWhiteSpace( p, encoding );
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
+ return 0;
+ }
+ if ( *p == '/' )
+ {
+ ++p;
+ // Empty tag.
+ if ( *p != '>' )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );
+ return 0;
+ }
+ return (p+1);
+ }
+ else if ( *p == '>' )
+ {
+ // Done with attributes (if there were any.)
+ // Read the value -- which can include other
+ // elements -- read the end tag, and return.
+ ++p;
+ p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens.
+ if ( !p || !*p ) {
+ // We were looking for the end tag, but found nothing.
+ // Fix for [ 1663758 ] Failure to report error on bad XML
+ if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
+ return 0;
+ }
+
+ // We should find the end tag now
+ if ( StringEqual( p, endTag.c_str(), false, encoding ) )
+ {
+ p += endTag.length();
+ return p;
+ }
+ else
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
+ return 0;
+ }
+ }
+ else
+ {
+ // Try to read an attribute:
+ TiXmlAttribute* attrib = new TiXmlAttribute();
+ if ( !attrib )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding );
+ return 0;
+ }
+
+ attrib->SetDocument( document );
+ pErr = p;
+ p = attrib->Parse( p, data, encoding );
+
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
+ delete attrib;
+ return 0;
+ }
+
+ // Handle the strange case of double attributes:
+ #ifdef TIXML_USE_STL
+ TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
+ #else
+ TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
+ #endif
+ if ( node )
+ {
+ node->SetValue( attrib->Value() );
+ delete attrib;
+ return 0;
+ }
+
+ attributeSet.Add( attrib );
+ }
+ }
+ return p;
+}
+
+
+const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ TiXmlDocument* document = GetDocument();
+
+ // Read in text and elements in any order.
+ const char* pWithWhiteSpace = p;
+ p = SkipWhiteSpace( p, encoding );
+
+ while ( p && *p )
+ {
+ if ( *p != '<' )
+ {
+ // Take what we have, make a text element.
+ TiXmlText* textNode = new TiXmlText( "" );
+
+ if ( !textNode )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding );
+ return 0;
+ }
+
+ if ( TiXmlBase::IsWhiteSpaceCondensed() )
+ {
+ p = textNode->Parse( p, data, encoding );
+ }
+ else
+ {
+ // Special case: we want to keep the white space
+ // so that leading spaces aren't removed.
+ p = textNode->Parse( pWithWhiteSpace, data, encoding );
+ }
+
+ if ( !textNode->Blank() )
+ LinkEndChild( textNode );
+ else
+ delete textNode;
+ }
+ else
+ {
+ // We hit a '<'
+ // Have we hit a new element or an end tag? This could also be
+ // a TiXmlText in the "CDATA" style.
+ if ( StringEqual( p, "</", false, encoding ) )
+ {
+ return p;
+ }
+ else
+ {
+ TiXmlNode* node = Identify( p, encoding );
+ if ( node )
+ {
+ p = node->Parse( p, data, encoding );
+ LinkEndChild( node );
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+ pWithWhiteSpace = p;
+ p = SkipWhiteSpace( p, encoding );
+ }
+
+ if ( !p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
+ }
+ return p;
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+ while ( in->good() )
+ {
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+ (*tag) += (char) c;
+
+ if ( c == '>' )
+ {
+ // All is well.
+ return;
+ }
+ }
+}
+#endif
+
+
+const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ TiXmlDocument* document = GetDocument();
+ p = SkipWhiteSpace( p, encoding );
+
+ if ( data )
+ {
+ data->Stamp( p, encoding );
+ location = data->Cursor();
+ }
+ if ( !p || !*p || *p != '<' )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
+ return 0;
+ }
+ ++p;
+ value = "";
+
+ while ( p && *p && *p != '>' )
+ {
+ value += *p;
+ ++p;
+ }
+
+ if ( !p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
+ }
+ if ( *p == '>' )
+ return p+1;
+ return p;
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+ while ( in->good() )
+ {
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+
+ (*tag) += (char) c;
+
+ if ( c == '>'
+ && tag->at( tag->length() - 2 ) == '-'
+ && tag->at( tag->length() - 3 ) == '-' )
+ {
+ // All is well.
+ return;
+ }
+ }
+}
+#endif
+
+
+const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ TiXmlDocument* document = GetDocument();
+ value = "";
+
+ p = SkipWhiteSpace( p, encoding );
+
+ if ( data )
+ {
+ data->Stamp( p, encoding );
+ location = data->Cursor();
+ }
+ const char* startTag = "<!--";
+ const char* endTag = "-->";
+
+ if ( !StringEqual( p, startTag, false, encoding ) )
+ {
+ document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
+ return 0;
+ }
+ p += strlen( startTag );
+
+ // [ 1475201 ] TinyXML parses entities in comments
+ // Oops - ReadText doesn't work, because we don't want to parse the entities.
+ // p = ReadText( p, &value, false, endTag, false, encoding );
+ //
+ // from the XML spec:
+ /*
+ [Definition: Comments may appear anywhere in a document outside other markup; in addition,
+ they may appear within the document type declaration at places allowed by the grammar.
+ They are not part of the document's character data; an XML processor MAY, but need not,
+ make it possible for an application to retrieve the text of comments. For compatibility,
+ the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity
+ references MUST NOT be recognized within comments.
+
+ An example of a comment:
+
+ <!-- declarations for <head> & <body> -->
+ */
+
+ value = "";
+ // Keep all the white space.
+ while ( p && *p && !StringEqual( p, endTag, false, encoding ) )
+ {
+ value.append( p, 1 );
+ ++p;
+ }
+ if ( p )
+ p += strlen( endTag );
+
+ return p;
+}
+
+
+const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ p = SkipWhiteSpace( p, encoding );
+ if ( !p || !*p ) return 0;
+
+// int tabsize = 4;
+// if ( document )
+// tabsize = document->TabSize();
+
+ if ( data )
+ {
+ data->Stamp( p, encoding );
+ location = data->Cursor();
+ }
+ // Read the name, the '=' and the value.
+ const char* pErr = p;
+ p = ReadName( p, &name, encoding );
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
+ return 0;
+ }
+ p = SkipWhiteSpace( p, encoding );
+ if ( !p || !*p || *p != '=' )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+ return 0;
+ }
+
+ ++p; // skip '='
+ p = SkipWhiteSpace( p, encoding );
+ if ( !p || !*p )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+ return 0;
+ }
+
+ const char* end;
+ const char SINGLE_QUOTE = '\'';
+ const char DOUBLE_QUOTE = '\"';
+
+ if ( *p == SINGLE_QUOTE )
+ {
+ ++p;
+ end = "\'"; // single quote in string
+ p = ReadText( p, &value, false, end, false, encoding );
+ }
+ else if ( *p == DOUBLE_QUOTE )
+ {
+ ++p;
+ end = "\""; // double quote in string
+ p = ReadText( p, &value, false, end, false, encoding );
+ }
+ else
+ {
+ // All attribute values should be in single or double quotes.
+ // But this is such a common error that the parser will try
+ // its best, even without them.
+ value = "";
+ while ( p && *p // existence
+ && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace
+ && *p != '/' && *p != '>' ) // tag end
+ {
+ if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {
+ // [ 1451649 ] Attribute values with trailing quotes not handled correctly
+ // We did not have an opening quote but seem to have a
+ // closing one. Give up and throw an error.
+ if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+ return 0;
+ }
+ value += *p;
+ ++p;
+ }
+ }
+ return p;
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+ while ( in->good() )
+ {
+ int c = in->peek();
+ if ( !cdata && (c == '<' ) )
+ {
+ return;
+ }
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+
+ (*tag) += (char) c;
+ in->get(); // "commits" the peek made above
+
+ if ( cdata && c == '>' && tag->size() >= 3 ) {
+ size_t len = tag->size();
+ if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {
+ // terminator of cdata.
+ return;
+ }
+ }
+ }
+}
+#endif
+
+const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+ value = "";
+ TiXmlDocument* document = GetDocument();
+
+ if ( data )
+ {
+ data->Stamp( p, encoding );
+ location = data->Cursor();
+ }
+
+ const char* const startTag = "<![CDATA[";
+ const char* const endTag = "]]>";
+
+ if ( cdata || StringEqual( p, startTag, false, encoding ) )
+ {
+ cdata = true;
+
+ if ( !StringEqual( p, startTag, false, encoding ) )
+ {
+ document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );
+ return 0;
+ }
+ p += strlen( startTag );
+
+ // Keep all the white space, ignore the encoding, etc.
+ while ( p && *p
+ && !StringEqual( p, endTag, false, encoding )
+ )
+ {
+ value += *p;
+ ++p;
+ }
+
+ TIXML_STRING dummy;
+ p = ReadText( p, &dummy, false, endTag, false, encoding );
+ return p;
+ }
+ else
+ {
+ bool ignoreWhite = true;
+
+ const char* end = "<";
+ p = ReadText( p, &value, ignoreWhite, end, false, encoding );
+ if ( p )
+ return p-1; // don't truncate the '<'
+ return 0;
+ }
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+ while ( in->good() )
+ {
+ int c = in->get();
+ if ( c <= 0 )
+ {
+ TiXmlDocument* document = GetDocument();
+ if ( document )
+ document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+ return;
+ }
+ (*tag) += (char) c;
+
+ if ( c == '>' )
+ {
+ // All is well.
+ return;
+ }
+ }
+}
+#endif
+
+const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
+{
+ p = SkipWhiteSpace( p, _encoding );
+ // Find the beginning, find the end, and look for
+ // the stuff in-between.
+ TiXmlDocument* document = GetDocument();
+ if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) )
+ {
+ if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
+ return 0;
+ }
+ if ( data )
+ {
+ data->Stamp( p, _encoding );
+ location = data->Cursor();
+ }
+ p += 5;
+
+ version = "";
+ encoding = "";
+ standalone = "";
+
+ while ( p && *p )
+ {
+ if ( *p == '>' )
+ {
+ ++p;
+ return p;
+ }
+
+ p = SkipWhiteSpace( p, _encoding );
+ if ( StringEqual( p, "version", true, _encoding ) )
+ {
+ TiXmlAttribute attrib;
+ p = attrib.Parse( p, data, _encoding );
+ version = attrib.Value();
+ }
+ else if ( StringEqual( p, "encoding", true, _encoding ) )
+ {
+ TiXmlAttribute attrib;
+ p = attrib.Parse( p, data, _encoding );
+ encoding = attrib.Value();
+ }
+ else if ( StringEqual( p, "standalone", true, _encoding ) )
+ {
+ TiXmlAttribute attrib;
+ p = attrib.Parse( p, data, _encoding );
+ standalone = attrib.Value();
+ }
+ else
+ {
+ // Read over whatever it is.
+ while( p && *p && *p != '>' && !IsWhiteSpace( *p ) )
+ ++p;
+ }
+ }
+ return 0;
+}
+
+bool TiXmlText::Blank() const
+{
+ for ( unsigned i=0; i<value.length(); i++ )
+ if ( !IsWhiteSpace( value[i] ) )
+ return false;
+ return true;
+}
+
diff --git a/output/Memory.xml b/output/Memory.xml
new file mode 100644
index 00000000..6eb79caa
--- /dev/null
+++ b/output/Memory.xml
@@ -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>
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 00000000..28c150c7
--- /dev/null
+++ b/tools/CMakeLists.txt
@@ -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) \ No newline at end of file
diff --git a/tools/cleanmap.cpp b/tools/cleanmap.cpp
new file mode 100644
index 00000000..af35193f
--- /dev/null
+++ b/tools/cleanmap.cpp
@@ -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;
+} \ No newline at end of file
diff --git a/tools/expbench.cpp b/tools/expbench.cpp
new file mode 100644
index 00000000..45a65587
--- /dev/null
+++ b/tools/expbench.cpp
@@ -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;
+} \ No newline at end of file
diff --git a/tools/prospector.cpp b/tools/prospector.cpp
new file mode 100644
index 00000000..f176449b
--- /dev/null
+++ b/tools/prospector.cpp
@@ -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;
+} \ No newline at end of file
diff --git a/tools/reveal.cpp b/tools/reveal.cpp
new file mode 100644
index 00000000..45fec732
--- /dev/null
+++ b/tools/reveal.cpp
@@ -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;
+} \ No newline at end of file