#include "le_fixup_record_table.hpp" #include "parse.hpp" #include "output.hpp" #include #include 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 ListOrOffsetT; typedef boost::variant DataT; typedef boost::optional, std::vector>>> AdditiveT; typedef boost::optional> SourcesT; typedef boost::variant V8orV16T; typedef boost::variant 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(is, "segment_number"); } else { internal.object_number = parse(is, "segment_number"); } if(bit(4, target_flags)) { internal.target_offset = parse(is, "target_offset"); } else { internal.target_offset = parse(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(is, "ordinal_value"); } else { ordinal.ordinal_number = parse(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(is, "ordinal_number"); } else { name.ordinal_number = parse(is, "ordinal_number"); } if(bit(4, target_flags)) { name.procedure_name_offset = parse(is, "procedure_name_offset"); } else { name.procedure_name_offset = parse(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(is, "entry_number"); } else { entry.entry_number = parse(is, "entry_number"); } return entry; } FixupRecordTable::Entry parse(std::istream& is) { using binparse::parse; FixupRecordTable::Entry entry; entry.source_flags = parse(is, "source_flags"); entry.target_flags = parse(is, "target_flags"); bool has_lists = bit(6, entry.source_flags); if(has_lists) { entry.source_offset_or_source_list_count = parse(is, "source_list_count"); } else { entry.source_offset_or_source_list_count = parse(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> vec; for(int i = 0; i < int(boost::get(entry.source_offset_or_source_list_count)); i++) { if(bit(5, entry.target_flags)) { vec.push_back(parse(is, "")); } else { vec.push_back(parse(is, "")); } } entry.additive = vec; } else { if(bit(5, entry.target_flags)) { entry.additive = parse(is, ""); } else { entry.additive = parse(is, ""); } } } if(has_lists) { std::vector vec; for(int i = 0; i < int(boost::get(entry.source_offset_or_source_list_count)); i++) { vec.push_back(parse(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(size_t i = 1; i < fixups.entries.size(); i++) { long current_pos = is.tellg(); long 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(static_cast(i))].push_back(x); } } return table; } std::ostream&operator<<(std::ostream& os, const FixupRecordTable& table) { return binparse::operator<<(os, table.entries); } }