summaryrefslogtreecommitdiff
path: root/le/le_fixup_record_table.cpp
diff options
context:
space:
mode:
authorDennis Brentjes <d.brentjes@gmail.com>2016-06-27 01:33:02 +0200
committerDennis Brentjes <d.brentjes@gmail.com>2016-06-27 15:23:06 +0200
commitb80a82fcc9edc73057796005cede4eea8380e193 (patch)
tree2da5e7cddef0bc39b449410c9826680a3dd6ca9d /le/le_fixup_record_table.cpp
parenta7bcede17b4c10e172c7877fc2ce89862dc454af (diff)
downloadopenwar-b80a82fcc9edc73057796005cede4eea8380e193.tar.gz
openwar-b80a82fcc9edc73057796005cede4eea8380e193.tar.bz2
openwar-b80a82fcc9edc73057796005cede4eea8380e193.zip
Parses the fixup page and fixup record table.
Diffstat (limited to 'le/le_fixup_record_table.cpp')
-rw-r--r--le/le_fixup_record_table.cpp237
1 files changed, 237 insertions, 0 deletions
diff --git a/le/le_fixup_record_table.cpp b/le/le_fixup_record_table.cpp
new file mode 100644
index 0000000..9331626
--- /dev/null
+++ b/le/le_fixup_record_table.cpp
@@ -0,0 +1,237 @@
+#include "le_fixup_record_table.hpp"
+
+#include "parse.hpp"
+#include "output.hpp"
+
+#include <boost/fusion/adapted/struct.hpp>
+#include <bitset>
+
+typedef le::FixupRecordTable::Entry Entry;
+typedef Entry::Internal Internal;
+typedef Entry::ImportedOrdinal ImportedOrdinal;
+typedef Entry::ImportedName ImportedName;
+typedef Entry::InternalEntry InternalEntry;
+
+typedef binparse::Offset16 Offset16;
+typedef binparse::Offset32 Offset32;
+typedef binparse::Value8 Value8;
+typedef binparse::Value16 Value16;
+
+typedef boost::variant<Offset16, Value8> ListOrOffsetT;
+typedef boost::variant<Internal, ImportedOrdinal, ImportedName, InternalEntry> DataT;
+typedef boost::optional<boost::variant<boost::variant<Offset16, Offset32>, std::vector<boost::variant<Offset16, Offset32>>>> AdditiveT;
+typedef boost::optional<std::vector<Value16>> SourcesT;
+
+typedef boost::variant<Value8,Value16> V8orV16T;
+typedef boost::variant<Offset16, Offset32> O16orO32T;
+
+BOOST_FUSION_ADAPT_STRUCT(
+ Internal,
+ (V8orV16T, object_number)
+ (O16orO32T, target_offset)
+)
+
+BOOST_FUSION_ADAPT_STRUCT(
+ ImportedOrdinal,
+ (V8orV16T, ordinal_number)
+)
+
+BOOST_FUSION_ADAPT_STRUCT(
+ ImportedName,
+ (V8orV16T, ordinal_number)
+ (O16orO32T, procedure_name_offset)
+)
+
+BOOST_FUSION_ADAPT_STRUCT(
+ InternalEntry,
+ (V8orV16T, entry_number)
+)
+
+BOOST_FUSION_ADAPT_STRUCT(
+ Entry,
+ (Value8, source_flags)
+ (Value8, target_flags)
+ (ListOrOffsetT, source_offset_or_source_list_count)
+ (DataT, data)
+ (AdditiveT, additive)
+ (SourcesT, sources)
+)
+
+namespace le {
+
+using namespace binparse;
+
+FixupRecordTable::Entry::Internal parse_internal(std::istream& is, Value8 target_flags) {
+ using binparse::parse;
+
+ FixupRecordTable::Entry::Internal internal;
+
+ if(bit(6, target_flags)) {
+ internal.object_number = parse<Value16>(is, "segment_number");
+ } else {
+ internal.object_number = parse<Value8>(is, "segment_number");
+ }
+
+ if(bit(4, target_flags)) {
+ internal.target_offset = parse<Offset32>(is, "target_offset");
+ } else {
+ internal.target_offset = parse<Offset16>(is, "target_offset");
+ }
+
+ return internal;
+}
+
+FixupRecordTable::Entry::ImportedOrdinal parse_imported_ordinal(std::istream& is, Value8 target_flags) {
+ using binparse::parse;
+
+ FixupRecordTable::Entry::ImportedOrdinal ordinal;
+
+ if(bit(6, target_flags)) {
+ ordinal.ordinal_number = parse<Value16>(is, "ordinal_value");
+ } else {
+ ordinal.ordinal_number = parse<Value8>(is, "ordinal_value");
+ }
+
+ return ordinal;
+}
+
+FixupRecordTable::Entry::ImportedName parse_imported_name(std::istream& is, Value8 target_flags) {
+ using binparse::parse;
+
+ FixupRecordTable::Entry::ImportedName name;
+
+ if(bit(6, target_flags)) {
+ name.ordinal_number = parse<Value16>(is, "ordinal_number");
+ } else {
+ name.ordinal_number = parse<Value8>(is, "ordinal_number");
+ }
+
+ if(bit(4, target_flags)) {
+ name.procedure_name_offset = parse<Offset32>(is, "procedure_name_offset");
+ } else {
+ name.procedure_name_offset = parse<Offset16>(is, "procedure_name_offset");
+ }
+
+ return name;
+}
+
+FixupRecordTable::Entry::InternalEntry parse_internal_entry(std::istream& is, Value8 target_flags) {
+ using binparse::parse;
+
+ FixupRecordTable::Entry::InternalEntry entry;
+
+ if(bit(6, target_flags)) {
+ entry.entry_number = parse<Value16>(is, "entry_number");
+ } else {
+ entry.entry_number = parse<Value8>(is, "entry_number");
+ }
+
+ return entry;
+}
+
+FixupRecordTable::Entry parse(std::istream& is)
+{
+ using binparse::parse;
+
+ FixupRecordTable::Entry entry;
+
+ entry.source_flags = parse<Value8>(is, "source_flags");
+ entry.target_flags = parse<Value8>(is, "target_flags");
+
+ bool has_lists = bit(6, entry.source_flags);
+ if(has_lists) {
+ entry.source_offset_or_source_list_count = parse<Value8>(is, "source_list_count");
+ } else {
+ entry.source_offset_or_source_list_count = parse<Offset16>(is, "source_offset");
+ }
+
+ auto relevant_flags = entry.target_flags & 3;
+
+ switch(relevant_flags) {
+ case 0: {
+ entry.data = parse_internal(is, entry.target_flags);
+ break;
+ }
+ case 1: {
+ entry.data = parse_imported_ordinal(is, entry.target_flags);
+ break;
+ }
+ case 2: {
+ entry.data = parse_imported_name(is, entry.target_flags);
+ break;
+ }
+ case 3: {
+ entry.data = parse_internal_entry(is, entry.target_flags);
+ break;
+ }
+ default: {
+ throw std::runtime_error("This cannot happen, value of relevant flags should be [0-3]");
+ }
+ }
+
+ if(relevant_flags == 0 or relevant_flags == 3) {
+ entry.additive.reset();
+ } else {
+ if(bit(2, entry.target_flags)) {
+ std::vector<boost::variant<Offset16, Offset32>> vec;
+ for(int i = 0; i < int(boost::get<Value8>(entry.source_offset_or_source_list_count)); i++) {
+ if(bit(5, entry.target_flags)) {
+ vec.push_back(parse<Offset32>(is, ""));
+ }
+ else {
+ vec.push_back(parse<Offset16>(is, ""));
+ }
+ }
+ entry.additive = vec;
+ } else {
+ if(bit(5, entry.target_flags)) {
+ entry.additive = parse<Offset32>(is, "");
+ }
+ else {
+ entry.additive = parse<Offset16>(is, "");
+ }
+ }
+ }
+
+ if(has_lists) {
+ std::vector<Value16> vec;
+ for(int i = 0; i < int(boost::get<Value8>(entry.source_offset_or_source_list_count)); i++) {
+ vec.push_back(parse<Value16>(is, ""));
+ }
+ entry.sources = vec;
+ } else {
+ entry.sources.reset();
+ }
+
+ return entry;
+}
+
+FixupRecordTable parse_fixup_record_table(std::istream& is, Offset32 offset, FixupPageTable fixups)
+{
+ is.seekg(offset, std::ios::beg);
+
+ FixupRecordTable table;
+
+ binparse::otreestream otree(std::cout);
+
+ for(int i = 1; i < fixups.entries.size(); i++) {
+ unsigned int current_pos = is.tellg();
+ unsigned int endpos = current_pos + (fixups.entries[i] - fixups.entries[i-1]);
+
+ while(current_pos = is.tellg(), current_pos < endpos) {
+ auto x = parse(is);
+ table.entries[Value32(i)].push_back(x);
+ }
+
+
+ }
+
+ return table;
+}
+
+std::ostream&operator<<(std::ostream& os, const FixupRecordTable& table)
+{
+ return binparse::operator<<(os, table.entries);
+}
+
+}