@@ -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 |"); | |||||
} |