src.dualinventive.com/jjacobs/dinetrpcll-sniffer/include/HexDump.h

154 lines
5.0 KiB
C++

// From https://gist.github.com/kristopherjohnson/90581f20aab44e669907
// Copyright (C) 2015 Kristopher Johnson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef net_kristopherjohnson_HexDump_h
#define net_kristopherjohnson_HexDump_h
#include <ios>
#include <iomanip>
#include <sstream>
#include <vector>
namespace HexDump {
using std::endl;
using std::hex;
using std::isprint;
using std::left;
using std::ostringstream;
using std::setfill;
using std::setw;
using std::size_t;
using std::vector;
// In the templates below, the type parameters must satisfy these constraints:
//
// - Stream: something like std::ostream or std::istream
//
// - InputStream: something like std::istream
//
// - OutputStream: something like std::ostream
//
// - ByteSequence: a collection of chars that can be iterated over, like std::vector<char>
const size_t BytesPerLine = 16;
// Saves original formatting state for a stream and
// restores that state before going out of scope
template<typename Stream>
class SavedState
{
public:
SavedState(Stream& s)
: stream(s), oldFlags(s.flags()), oldFill(s.fill())
{}
~SavedState() { stream.flags(oldFlags); stream.fill(oldFill); }
SavedState(const SavedState&) = delete;
void operator=(const SavedState&) = delete;
private:
Stream& stream;
decltype(stream.flags()) oldFlags;
decltype(stream.fill()) oldFill;
};
// Dump a sequence of bytes as hex with spaces between; e.g., "cf fa 4f a0 "
template<typename OutputStream, typename ByteSequence>
void dumpBytesAsHex(OutputStream& output, const ByteSequence& bytes)
{
SavedState<OutputStream> savedState{ output };
output << hex << setfill('0');
for (auto byte: bytes) {
unsigned widenedUIntValue = static_cast<unsigned char>(byte);
output << setw(2) << widenedUIntValue << " ";
}
}
// Dump a sequence of bytes as ASCII characters,
// substituting '.' for non-printing characters
template<typename OutputStream, typename ByteSequence>
void dumpBytesAsText(OutputStream& output, const ByteSequence& bytes)
{
for (auto byte: bytes)
output.put(isprint(byte) ? byte : '.');
}
// Dump a sequence of bytes in side-by-side hex and text formats
template<typename OutputStream, typename ByteSequence>
void dumpHexLine(OutputStream& output, const ByteSequence& bytes)
{
SavedState<OutputStream> savedState{ output };
ostringstream hexStream;
dumpBytesAsHex(hexStream, bytes);
const auto HexOutputWidth = BytesPerLine * 3 + 1;
output << setw(HexOutputWidth) << left << hexStream.str();
dumpBytesAsText(output, bytes);
output << endl;
}
// Dump a sequence of bytes in side-by-side hex and text formats,
// prefixed with a hex offset
template<typename OutputStream, typename ByteSequence>
void dumpHexLine(OutputStream& output, size_t offset, const ByteSequence& bytes)
{
{
SavedState<OutputStream> savedState{ output };
output << setw(8) << setfill('0') << hex
<< offset << " ";
}
dumpHexLine(output, bytes);
}
// Dump bytes from input stream in side-by-side hex and text formats
template<typename OutputStream, typename InputStream>
void dumpStream(OutputStream& output, InputStream& input)
{
vector<char> bytesToDump;
bytesToDump.reserve(BytesPerLine);
size_t offset = 0;
char byte;
while (input.get(byte)) {
bytesToDump.push_back(byte);
if (bytesToDump.size() == BytesPerLine) {
dumpHexLine(output, offset, bytesToDump);
bytesToDump.clear();
offset += BytesPerLine;
}
}
if (!bytesToDump.empty())
dumpHexLine(output, offset, bytesToDump);
}
} // namespace HexDump
#endif /* net_kristopherjohnson_HexDump_h */