summaryrefslogtreecommitdiff
path: root/library/VersionInfoFactory.cpp
diff options
context:
space:
mode:
authorPetr Mrázek2010-08-20 14:10:05 +0200
committerPetr Mrázek2010-08-20 14:10:05 +0200
commit1bceac23433fa097e4b5d43aa3eb1999a370872f (patch)
tree5e1297dfc3145e8261c37f891193f2c48c459bec /library/VersionInfoFactory.cpp
parent3b29fddf7bb4851f77a707f32effa77cb3b1a466 (diff)
downloaddfhack-1bceac23433fa097e4b5d43aa3eb1999a370872f.tar.gz
dfhack-1bceac23433fa097e4b5d43aa3eb1999a370872f.tar.bz2
dfhack-1bceac23433fa097e4b5d43aa3eb1999a370872f.tar.xz
Rename memory_info and its factory class.
Diffstat (limited to 'library/VersionInfoFactory.cpp')
-rw-r--r--library/VersionInfoFactory.cpp295
1 files changed, 295 insertions, 0 deletions
diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp
new file mode 100644
index 00000000..6f2e6a32
--- /dev/null
+++ b/library/VersionInfoFactory.cpp
@@ -0,0 +1,295 @@
+/*
+www.sourceforge.net/projects/dfhack
+Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#include "Internal.h"
+#include "VersionInfoFactory.h"
+
+#include "dfhack/VersionInfo.h"
+#include "dfhack/DFError.h"
+
+using namespace DFHack;
+
+VersionInfoFactory::~VersionInfoFactory()
+{
+ // for each in std::vector<memory_info*> meminfo;, delete
+ for(uint32_t i = 0; i < meminfo.size();i++)
+ {
+ delete meminfo[i];
+ }
+ meminfo.clear();
+}
+
+void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem)
+{
+ TiXmlElement* pClassEntry;
+ TiXmlElement* pClassSubEntry;
+ // check for rebase, do rebase if check positive
+ const char * rebase = vtable->Attribute("rebase");
+ if(rebase)
+ {
+ int32_t rebase_offset = strtol(rebase, NULL, 16);
+ mem->RebaseVTable(rebase_offset);
+ }
+ // parse vtable entries
+ 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");
+ uint32_t vtable = 0;
+ if(cstr_vtable)
+ vtable = strtol(cstr_vtable, NULL, 16);
+ // it's a simple class
+ if(type== "class")
+ {
+ mem->setClass(cstr_name, vtable);
+ }
+ // it's a multi-type class
+ else if (type == "multiclass")
+ {
+ // get offset of the type variable
+ const char *cstr_typeoffset = pClassEntry->Attribute("typeoffset");
+ uint32_t typeoffset = 0;
+ if(cstr_typeoffset)
+ typeoffset = strtol(cstr_typeoffset, NULL, 16);
+ t_class * mclass = mem->setClass(cstr_name, vtable, typeoffset);
+ // parse class sub-entries
+ pClassSubEntry = pClassEntry->FirstChildElement();
+ for(;pClassSubEntry;pClassSubEntry=pClassSubEntry->NextSiblingElement())
+ {
+ type = pClassSubEntry->Value();
+ if(type== "class")
+ {
+ // type is a value loaded from type offset
+ cstr_name = pClassSubEntry->Attribute("name");
+ const char *cstr_value = pClassSubEntry->Attribute("type");
+ mem->setClassChild(mclass,cstr_name,cstr_value);
+ }
+ }
+ }
+ }
+}
+
+void VersionInfoFactory::ParseEntry (TiXmlElement* entry, VersionInfo* 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);
+ }
+
+ if (!cstr_version)
+ throw Error::MemoryXmlBadAttribute("version");
+ if (!cstr_os)
+ throw Error::MemoryXmlBadAttribute("os");
+
+ 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 if ( os == "all")
+ {
+ // yay
+ }
+ else
+ {
+ throw Error::MemoryXmlBadAttribute("os");
+ }
+
+ // 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();
+
+ if(!cstr_value)
+ cstr_value = pMemEntry->Attribute("id");
+
+ // check for missing parts
+ string type, name, value;
+ type = cstr_type;
+ if(type == "VTable")
+ {
+ ParseVTable(pMemEntry, mem);
+ continue;
+ }
+ if(!(cstr_name && cstr_value))
+ {
+ throw Error::MemoryXmlUnderspecifiedEntry(cstr_version);
+ }
+ 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 if (type == "Profession")
+ {
+ mem->setProfession(value,name);
+ }
+ else if (type == "Job")
+ {
+ mem->setJob(value,name);
+ }
+ else if (type == "Skill")
+ {
+ mem->setSkill(value,name);
+ }
+ else if (type == "Trait")
+ {
+ mem->setTrait(value, name,pMemEntry->Attribute("level_0"),pMemEntry->Attribute("level_1"),pMemEntry->Attribute("level_2"),pMemEntry->Attribute("level_3"),pMemEntry->Attribute("level_4"),pMemEntry->Attribute("level_5"));
+ }
+ else if (type == "Labor")
+ {
+ mem->setLabor(value,name);
+ }
+ else if (type == "Level")
+ {
+ mem->setLevel(value, name, pMemEntry->Attribute("xpNxtLvl"));
+ }
+ else if (type == "Mood")
+ {
+ mem->setMood(value, name);
+ }
+ else
+ {
+ throw Error::MemoryXmlUnknownType(type.c_str());
+ }
+ } // for
+} // method
+
+VersionInfoFactory::VersionInfoFactory(string path_to_xml)
+{
+ error = false;
+ loadFile(path_to_xml);
+}
+
+// load the XML file with offsets
+bool VersionInfoFactory::loadFile(string path_to_xml)
+{
+ TiXmlDocument doc( path_to_xml.c_str() );
+ //bool loadOkay = doc.LoadFile();
+ if (!doc.LoadFile())
+ {
+ error = true;
+ throw Error::MemoryXmlParse(doc.ErrorDesc(), doc.ErrorId(), doc.ErrorRow(), doc.ErrorCol());
+ }
+ TiXmlHandle hDoc(&doc);
+ TiXmlElement* pElem;
+ TiXmlHandle hRoot(0);
+ VersionInfo mem;
+
+ // block: name
+ {
+ pElem=hDoc.FirstChildElement().Element();
+ // should always have a valid root but handle gracefully if it does
+ if (!pElem)
+ {
+ error = true;
+ throw Error::MemoryXmlNoRoot();
+ }
+ string m_name=pElem->Value();
+ if(m_name != "DFHack")
+ {
+ error = true;
+ throw Error::MemoryXmlNoRoot();
+ }
+ // save this for later
+ hRoot=TiXmlHandle(pElem);
+ }
+ // transform elements
+ {
+ // trash existing list
+ for(uint32_t i = 0; i < meminfo.size(); i++)
+ {
+ delete meminfo[i];
+ }
+ 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 = pMemInfo->Attribute("id");
+ if(id)
+ {
+ string str_id = id;
+ map_pNamedEntries[str_id] = pMemInfo;
+ }
+ }
+ for(uint32_t i = 0; i< v_pEntries.size();i++)
+ {
+ VersionInfo *mem = new VersionInfo();
+ //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
+ }
+ error = false;
+ return true;
+}