| @@ -2,6 +2,7 @@ | |||||
| #include "misc/exception.h" | #include "misc/exception.h" | ||||
| #include "misc/flags.h" | #include "misc/flags.h" | ||||
| #include "misc/hexdump.h" | |||||
| #include "misc/indent.h" | #include "misc/indent.h" | ||||
| #include "misc/stream.h" | #include "misc/stream.h" | ||||
| #include "misc/type_helper.h" | #include "misc/type_helper.h" | ||||
| @@ -0,0 +1,56 @@ | |||||
| #pragma once | |||||
| #include <iostream> | |||||
| namespace cppcore | |||||
| { | |||||
| /** | |||||
| * @brief Helper class to print hexdumps. | |||||
| */ | |||||
| struct hexdump | |||||
| { | |||||
| const void * data; //!< Data to dump. | |||||
| size_t len; //!< Number of bytes stored in data. | |||||
| size_t offset; //!< Offset to start numbering at (this will not affect the passed data pointer). | |||||
| size_t split; //!< Add extra colum after specified number of bytes. | |||||
| size_t newline; //!< Add new line after specified number of bytes. | |||||
| /** | |||||
| * Constructor. | |||||
| * | |||||
| * @param[in] p_data Data to dump. | |||||
| * @param[in] p_len Number of bytes stored in @data. | |||||
| * @param[in] p_offset Offset to start numbering at (this will not affect the passed data pointer). | |||||
| * @param[in] p_split Add extra colum after specified number of bytes. | |||||
| * @param[in] p_newline Add new line after specified number of bytes. | |||||
| */ | |||||
| inline hexdump( | |||||
| const void * p_data, | |||||
| size_t p_len, | |||||
| size_t p_offset = 0, | |||||
| size_t p_split = 8, | |||||
| size_t p_newline = 16); | |||||
| /** | |||||
| * @pbrief Print the hexdump to the passed stream. | |||||
| */ | |||||
| inline void print(std::ostream& os) const; | |||||
| }; | |||||
| } | |||||
| namespace std | |||||
| { | |||||
| /** | |||||
| * @brief Write the helper class to stream using the << operator. | |||||
| */ | |||||
| template<typename T_char, typename T_traits> | |||||
| inline basic_ostream<T_char, T_traits>& operator<< ( | |||||
| basic_ostream<T_char, T_traits>& os, | |||||
| const cppcore::hexdump& d); | |||||
| } | |||||
| #include "hexdump.inl" | |||||
| @@ -0,0 +1,89 @@ | |||||
| #pragma once | |||||
| #include <iomanip> | |||||
| #include "hexdump.h" | |||||
| namespace cppcore | |||||
| { | |||||
| /* hexdump */ | |||||
| hexdump::hexdump( | |||||
| const void * p_data, | |||||
| size_t p_len, | |||||
| size_t p_offset, | |||||
| size_t p_split, | |||||
| size_t p_newline) | |||||
| : data (p_data) | |||||
| , len (p_len) | |||||
| , offset (p_offset) | |||||
| , split (p_split) | |||||
| , newline (p_newline) | |||||
| { } | |||||
| void hexdump::print(std::ostream& os) const | |||||
| { | |||||
| using namespace ::std; | |||||
| const uint8_t * p = static_cast<const uint8_t*>(data); | |||||
| size_t i = 0; | |||||
| size_t l = 0; | |||||
| std::string s; | |||||
| while (i < len) | |||||
| { | |||||
| if (i % newline == 0) | |||||
| { | |||||
| os << hex << setw(8) << setfill('0') << (offset + i); | |||||
| } | |||||
| if (l % split == 0) | |||||
| { | |||||
| os.put(' '); | |||||
| s.push_back('|'); | |||||
| } | |||||
| s.push_back(std::isprint(p[i]) | |||||
| ? static_cast<char>(p[i]) | |||||
| : '.'); | |||||
| os << " " << hex << setw(2) << setfill('0') << static_cast<int>(p[i]); | |||||
| ++l; | |||||
| ++i; | |||||
| if (i % newline == 0) | |||||
| { | |||||
| os << " " << s << "|" << endl; | |||||
| s.clear(); | |||||
| l = 0; | |||||
| } | |||||
| } | |||||
| if (l > 0) | |||||
| { | |||||
| auto rest = (newline - l); | |||||
| auto fill = (rest / split); | |||||
| os << std::string(3 * rest + fill, ' ') | |||||
| << " " << s << std::string(rest + fill, ' ') << "|"; | |||||
| } | |||||
| } | |||||
| } | |||||
| namespace std | |||||
| { | |||||
| /** | |||||
| * @brief Write the helper class to stream using the << operator. | |||||
| */ | |||||
| template<typename T_char, typename T_traits> | |||||
| inline basic_ostream<T_char, T_traits>& operator<< ( | |||||
| basic_ostream<T_char, T_traits>& os, | |||||
| const cppcore::hexdump& d) | |||||
| { | |||||
| d.print(os); | |||||
| return os; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,19 @@ | |||||
| #include <gtest/gtest.h> | |||||
| #include <cppcore/misc/hexdump.h> | |||||
| using namespace ::cppcore; | |||||
| using namespace ::testing; | |||||
| TEST(hexdump_tests, simple) | |||||
| { | |||||
| std::string s("ahgiupiPTIBPHgGHIbt974ht hPVIb pg ZTPGTiBGBKGSGSQT20Z4TNVK AQHZQ"); | |||||
| std::ostringstream ss; | |||||
| ss << hexdump(s.data(), s.size(), 123, 4); | |||||
| EXPECT_EQ( | |||||
| ss.str(), | |||||
| "0000007b 61 68 67 69 75 70 69 50 54 49 42 50 48 67 47 48 |ahgi|upiP|TIBP|HgGH|\n" | |||||
| "0000008b 49 62 74 39 37 34 68 74 20 68 50 56 49 62 20 70 |Ibt9|74ht| hPV|Ib p|\n" | |||||
| "0000009b 67 20 5a 54 50 47 54 69 42 47 42 4b 47 53 47 53 |g ZT|PGTi|BGBK|GSGS|\n" | |||||
| "000000ab 51 54 32 30 5a 34 54 4e 56 4b 20 20 41 51 48 5a |QT20|Z4TN|VK |AQHZ|\n" | |||||
| "000000bb 51 |Q |"); | |||||
| } | |||||