diff options
| author | Dennis Brentjes <d.brentjes@gmail.com> | 2016-06-27 01:33:02 +0200 |
|---|---|---|
| committer | Dennis Brentjes <d.brentjes@gmail.com> | 2016-06-27 15:23:06 +0200 |
| commit | b80a82fcc9edc73057796005cede4eea8380e193 (patch) | |
| tree | 2da5e7cddef0bc39b449410c9826680a3dd6ca9d /le/le_fixup_record_table.cpp | |
| parent | a7bcede17b4c10e172c7877fc2ce89862dc454af (diff) | |
| download | openwar-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.cpp | 237 |
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); +} + +} |
