diff options
| author | Dennis Brentjes <d.brentjes@gmail.com> | 2016-06-19 11:58:16 +0200 |
|---|---|---|
| committer | Dennis Brentjes <d.brentjes@gmail.com> | 2016-06-19 11:58:16 +0200 |
| commit | c66d1f5c0af70161f4ad4c4175f4280e95b55dfd (patch) | |
| tree | f8e5e5d6dc921054182e478be742ac30258c56c6 | |
| download | openwar-c66d1f5c0af70161f4ad4c4175f4280e95b55dfd.tar.gz openwar-c66d1f5c0af70161f4ad4c4175f4280e95b55dfd.tar.bz2 openwar-c66d1f5c0af70161f4ad4c4175f4280e95b55dfd.zip | |
Initial commit of a mz-header parser.
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | CMakeLists.txt | 7 | ||||
| -rw-r--r-- | fusion-utils/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | fusion-utils/index_list.hpp | 16 | ||||
| -rw-r--r-- | mz/CMakeLists.txt | 32 | ||||
| -rw-r--r-- | mz/mz_header.cpp | 116 | ||||
| -rw-r--r-- | mz/mz_header.hpp | 47 | ||||
| -rw-r--r-- | mz/mz_header_parser.cpp | 56 |
8 files changed, 289 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6e83be0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build* +CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..24fb61f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.5.2) + +project(openwar) + +add_subdirectory(fusion-utils) +add_subdirectory(mz) + diff --git a/fusion-utils/CMakeLists.txt b/fusion-utils/CMakeLists.txt new file mode 100644 index 0000000..50e8565 --- /dev/null +++ b/fusion-utils/CMakeLists.txt @@ -0,0 +1,13 @@ +find_package(Boost REQUIRED) + +add_library(fusion-utils STATIC + index_list.hpp +) + +target_include_directories(fusion-utils + PUBLIC ${Boost_INCLUDE_DIRS} + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} +) + +set_target_properties(fusion-utils PROPERTIES LINKER_LANGUAGE CXX) + diff --git a/fusion-utils/index_list.hpp b/fusion-utils/index_list.hpp new file mode 100644 index 0000000..f363dc3 --- /dev/null +++ b/fusion-utils/index_list.hpp @@ -0,0 +1,16 @@ +#pragma once + +template<int... Indices> +struct indices { + typedef indices<Indices..., sizeof...(Indices)> next; +}; + +template<int N> +struct build_indices { + typedef typename build_indices<N - 1>::type::next type; +}; + +template<> +struct build_indices<0> { + typedef indices<> type; +}; diff --git a/mz/CMakeLists.txt b/mz/CMakeLists.txt new file mode 100644 index 0000000..aad239b --- /dev/null +++ b/mz/CMakeLists.txt @@ -0,0 +1,32 @@ +add_library(mz STATIC + mz_header.hpp mz_header.cpp +) + +target_include_directories(mz + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(mz + PUBLIC fusion-utils +) + +target_compile_options(mz + PUBLIC "-std=c++14" +) + +find_package(Boost COMPONENTS filesystem program_options system REQUIRED) + +add_executable(mz_header_parser + mz_header_parser.cpp +) + +target_include_directories(mz_header_parser + PRIVATE ${Boost_INCLUDE_DIRS} +) + +target_link_libraries(mz_header_parser + PRIVATE mz + PRIVATE ${Boost_LIBRARIES} +) + + diff --git a/mz/mz_header.cpp b/mz/mz_header.cpp new file mode 100644 index 0000000..e6d4461 --- /dev/null +++ b/mz/mz_header.cpp @@ -0,0 +1,116 @@ +#include "mz_header.hpp" +#include "index_list.hpp" + +#include <boost/fusion/adapted/struct.hpp> +#include <boost/fusion/adapted/struct/detail/extension.hpp> + +#include <vector> +#include <iomanip> + +UnexpectedEOS::UnexpectedEOS() +: std::runtime_error("Unexpected end of stream.") +{} + +UnexpectedEOS::UnexpectedEOS(std::__cxx11::string location) +: std::runtime_error("Unexpected end of stream after " + location) +{} + +NotAMZFileException::NotAMZFileException() +: std::runtime_error("This stream does not contain a valid MZ executable") +{} + +BOOST_FUSION_ADAPT_STRUCT( + MZHeader, + (Magic, magic) + (uint16_t, bytes_in_last_block) + (uint16_t, blocks_in_file) + (uint16_t, num_relocs) + (uint16_t, header_paragraphs) + (uint16_t, min_extra_paragraphs) + (uint16_t, max_extra_paragraphs) + (uint16_t, ss) + (uint16_t, sp) + (uint16_t, checksum) + (uint16_t, ip) + (uint16_t, cs) + (uint16_t, reloc_table_offset) + (uint16_t, overlay_number) +) + +template<typename T> +T parse(std::istream& is, std::string name); + +template<> +uint16_t parse<uint16_t>(std::istream& is, std::string name) { + if(!is) { + throw UnexpectedEOS(); + } + char data[2] = {0, 0}; + is.read(data, 2); + if(!is) { + throw UnexpectedEOS(name); + } + + return (((unsigned char) data[1]) << 8) | (unsigned char) data[0]; +} + +template<> +Magic parse<Magic>(std::istream& is, std::string name) { + if(!is) { + throw UnexpectedEOS(); + } + char data[2]; + is.read(data, 2); + if(!is) { + throw UnexpectedEOS(name); + } + + return static_cast<Magic>((data[1] << 8) | data[0]); +} + +template <int... Indices> +MZHeader parse_mz_file_impl(std::istream& is, indices<Indices...>) { + + return {parse<typename std::decay<typename boost::fusion::result_of::at_c<MZHeader, Indices>::type>::type>(is, boost::fusion::extension::struct_member_name<MZHeader, Indices>::call())...}; + +} + +MZHeader parse_mz_file(std::istream& is) { + + typedef build_indices<boost::fusion::result_of::size<MZHeader>::value>::type indices; + + return parse_mz_file_impl(is, indices{}); +} + +std::ostream& output_impl(std::ostream& os, MZHeader const&, indices<>) { + return os; +} + +template<typename T> +std::ostream& output(std::ostream& os, T rh) { + return os << std::hex << std::setw(sizeof(T) * 2) << std::setfill('0') << rh << std::endl; +} + +std::string to_string(Magic magic) { + char* c = reinterpret_cast<char*>(&magic); + return std::string(c, sizeof(Magic)); +} + +template <> +std::ostream& output<Magic>(std::ostream& os, Magic m) { + return os << std::hex << std::setw(4) << std::setfill('0') << m << " (" << to_string(m) << ")" << std::endl; +} + +template <int I, int... Indices> +std::ostream& output_impl(std::ostream& os, const MZHeader& header, indices<I, Indices...>) { + os << boost::fusion::extension::struct_member_name<MZHeader, I>::call() << ": "; + output(os, boost::fusion::at_c<I>(header)); + return output_impl(os, header, indices<Indices...>{}); +} + +std::ostream& operator<<(std::ostream& os, MZHeader const& header) +{ + typedef build_indices<boost::fusion::result_of::size<MZHeader>::value>::type indices; + + return output_impl(os, header, indices{}); +} diff --git a/mz/mz_header.hpp b/mz/mz_header.hpp new file mode 100644 index 0000000..ad5f419 --- /dev/null +++ b/mz/mz_header.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include <cstdint> +#include <cstddef> +#include <stdexcept> +#include <istream> +#include <ostream> + +#include <boost/serialization/strong_typedef.hpp> + +BOOST_STRONG_TYPEDEF(uint16_t, Magic); + +struct NotAMZFileException : public std::runtime_error { + NotAMZFileException(); +}; + +struct UnexpectedEOS : public std::runtime_error { + UnexpectedEOS(); + + UnexpectedEOS(std::string location); +}; + +struct MZHeader { + Magic magic; + uint16_t bytes_in_last_block; + uint16_t blocks_in_file; + uint16_t num_relocs; + uint16_t header_paragraphs; + uint16_t min_extra_paragraphs; + uint16_t max_extra_paragraphs; + uint16_t ss; + uint16_t sp; + uint16_t checksum; + uint16_t ip; + uint16_t cs; + uint16_t reloc_table_offset; + uint16_t overlay_number; +}; + +uint16_t parse_uint16_t(std::istream& is, std::string name = ""); + +MZHeader parse_mz_file(std::istream& is); + +void print_mz_header(MZHeader const& header); + +std::ostream& operator<<(std::ostream& os, MZHeader const& header); + diff --git a/mz/mz_header_parser.cpp b/mz/mz_header_parser.cpp new file mode 100644 index 0000000..d18a72e --- /dev/null +++ b/mz/mz_header_parser.cpp @@ -0,0 +1,56 @@ + +#include "mz_header.hpp" + +#include <boost/program_options.hpp> +#include <boost/filesystem.hpp> + +#include <iostream> + +int main(int argc, char* argv[]) { + boost::program_options::options_description description; + description.add_options() + ("help,h", "produces this help message") + ("exe,e", boost::program_options::value<std::string>(), "The MZ executable to parse the header for.") + ; + + boost::program_options::variables_map vm; + boost::program_options::store(boost::program_options::parse_command_line(argc, argv, description), vm); + boost::program_options::notify(vm); + + if(vm.count("help")) { + std::cout << description << std::endl; + return 0; + } + + boost::filesystem::path file_path; + if(vm.count("exe")) { + std::string exe_file = vm["exe"].as<std::string>(); + + if(boost::filesystem::exists(exe_file)) { + if(!boost::filesystem::is_directory(exe_file)) { + file_path = exe_file; + } else { + std::cerr << exe_file << " is a folder" << std::endl; + std::cerr << std::endl; + std::cerr << description << std::endl; + return -1; + } + } else { + std::cerr << "file: " << exe_file << " does not exist" << std::endl; + std::cerr << std::endl; + std::cerr << description << std::endl; + return -1; + } + } else { + std::cerr << "Option \"exe_file\" is required"; + std::cerr << std::endl; + std::cerr << description << std::endl; + return -1; + } + + std::ifstream file(file_path.string()); + auto x = parse_mz_file(file); + std::cout << x << std::endl; + + return 0; +}
\ No newline at end of file |
