6
\$\begingroup\$

We had a little bit of fun in the 2nd Monitor this morning, one user greeted another with a hex string. It turned out that the user being greeted deals with Hex Dumps enough that they were able to read the string, but I wasn't so I created this converter.

What could I have done to reduce the dependency on cstring?

How could I have made this more C++17 and less C Programming language.

#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>

class HexStringToAsciiStringConverter
{
    std::vector<unsigned> HexValues;

    const char* Remove0x(const char* hxv)
    {
        if (std::strstr(hxv, "0x") == hxv)
        {
            hxv += 2;
        }

        return hxv;
    }

    void ConvertStringToUnsigned(std::string HexStringToConvert)
    {
        const char *hxv = Remove0x(HexStringToConvert.c_str());
        while (*hxv && *(hxv+1))
        {
            char hxva[3] = {'\0'};
            std::strncpy(hxva, hxv, 2);
            HexValues.push_back(std::strtol(hxva, nullptr, 16));
            hxv += 2;
        }
    }

public:
    HexStringToAsciiStringConverter::HexStringToAsciiStringConverter(std::string Original)
    {
        ConvertStringToUnsigned(Original);
    }

    std::string HexStringToAsciiStringConverter::ConvertHexToString()
    {
        std::vector<unsigned char> tmpcarray;
        for (auto HexValue: HexValues)
        {
            tmpcarray.push_back(HexValue);
        }

        std::string output(tmpcarray.begin(), tmpcarray.end());

        return output;
    }
};

int main() {
    std::string Original = "0x486920446f6e2c20686f7727732073706163653f";

    HexStringToAsciiStringConverter Converter(Original);
    std::cout << Converter.ConvertHexToString() << std::endl;

    return EXIT_SUCCESS;
}
\$\endgroup\$
  • 1
    \$\begingroup\$ It's only ASCII if that's the native encoding on your system. It would be better named as a "hex to raw text convertor". \$\endgroup\$ – Toby Speight Oct 10 at 9:49
  • \$\begingroup\$ @TobySpeight Thank you for pointing that out. \$\endgroup\$ – pacmaninbw Oct 10 at 15:01
4
\$\begingroup\$

I'm surprised that, according to your code, C++ doesn't have a strip_prefix or without_beginning or skip_start function to skip over the initial "0x". If there were one, you should definitely use that instead of implementing your own. Do a little search, I'm sure such a function exists.

Even though this is C++, there is no need to write a class for a simple conversion function like this. In my experience, this task can be solved in less than 20 lines of code, and there is no state that you need to save between method calls, therefore a class is unnecessary. Just write an ordinary std::string hex_to_bytes(const std::string_view &hex) function.

As far as I remember, std::string has a push_back method, therefore there's no need to use an intermediate vector for building up the string.

My rough idea is:

std::string hex_to_bytes(const std::string_view &hex) {
    std::size_t i = 0, size = hex.size();
    if (size >= 2 && hex[0] == '0' && hex[1] == 'x')
        i += 2;

    std::string result;
    for (; i + 1 < size; i += 2) {
        char octet_chars[] = { hex[i], hex[i + 1], '\0' };

        char *end;
        unsigned long octet = std::strtoul(octet_chars, &end, 16);
        if (end != octet_chars + 2)
            throw std::some_exception();

        result.push_back(static_cast<char>(octet));
    }

    if (i != size)
        throw std::some_exception();

    return result;
}

I didn't test the above code. It also doesn't look very C++-like to me because it accesses the character array directly. But probably, for this kind of functions, there is no high-level way of expressing the code.


By the way, instead of writing all this code, you could also write a Perl one-liner:

perl -pe '$_ = pack("H*", $1) if /([0-9a-f]+)/i'
\$\endgroup\$
  • \$\begingroup\$ I created a class because I plan to embed it in a tool later, however, the class will have to be able to go both ways so it will probably be renamed. \$\endgroup\$ – pacmaninbw Oct 10 at 14:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.