summaryrefslogtreecommitdiff
path: root/indra/test/hexdump.h
blob: dd7cbaaa3c56eecd1f05612be20137d8de678a5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/**
 * @file   hexdump.h
 * @author Nat Goodspeed
 * @date   2023-09-08
 * @brief  Provide hexdump() and hexmix() ostream formatters
 * 
 * $LicenseInfo:firstyear=2023&license=viewerlgpl$
 * Copyright (c) 2023, Linden Research, Inc.
 * $/LicenseInfo$
 */

#if ! defined(LL_HEXDUMP_H)
#define LL_HEXDUMP_H

#include <cctype>
#include <iomanip>
#include <iostream>
#include <string_view>

// Format a given byte string as 2-digit hex values, no separators
// Usage: std::cout << hexdump(somestring) << ...
class hexdump
{
public:
    hexdump(const std::string_view& data):
        hexdump(data.data(), data.length())
    {}

    hexdump(const char* data, size_t len):
        hexdump(reinterpret_cast<const unsigned char*>(data), len)
    {}

    hexdump(const unsigned char* data, size_t len):
        mData(data, data + len)
    {}

    friend std::ostream& operator<<(std::ostream& out, const hexdump& self)
    {
        auto oldfmt{ out.flags() };
        auto oldfill{ out.fill() };
        out.setf(std::ios_base::hex, std::ios_base::basefield);
        out.fill('0');
        for (auto c : self.mData)
        {
            out << std::setw(2) << unsigned(c);
        }
        out.setf(oldfmt, std::ios_base::basefield);
        out.fill(oldfill);
        return out;
    }

private:
    std::vector<unsigned char> mData;
};

// Format a given byte string as a mix of printable characters and, for each
// non-printable character, "\xnn"
// Usage: std::cout << hexmix(somestring) << ...
class hexmix
{
public:
    hexmix(const std::string_view& data):
        mData(data)
    {}

    hexmix(const char* data, size_t len):
        mData(data, len)
    {}

    friend std::ostream& operator<<(std::ostream& out, const hexmix& self)
    {
        auto oldfmt{ out.flags() };
        auto oldfill{ out.fill() };
        out.setf(std::ios_base::hex, std::ios_base::basefield);
        out.fill('0');
        for (auto c : self.mData)
        {
            // std::isprint() must be passed an unsigned char!
            if (std::isprint(static_cast<unsigned char>(c)))
            {
                out << c;
            }
            else
            {
                out << "\\x" << std::setw(2) << unsigned(c);
            }
        }
        out.setf(oldfmt, std::ios_base::basefield);
        out.fill(oldfill);
        return out;
    }

private:
    std::string mData;
};

#endif /* ! defined(LL_HEXDUMP_H) */