21

Declaration of a method are following:

//some.h
void TDES_Decryption(BYTE *Data, BYTE *Key, BYTE *InitalVector, int Length);

I am calling this method from the following code:

//some.c
extern "C" __declspec(dllexport) bool _cdecl OnDecryption(LPCTSTR stringKSN, LPCTSTR BDK){
    TDES_Decryption(m_Track1Buffer, m_cryptoKey, init_vector, len);
    return m_Track1Buffer;
}

Where as data type of m_Track1Buffer is BYTE m_Track1Buffer[1000]; Now i want to make some changes in above method i.e. want to return the String in hex instead of Byte. How should i convert this m_Track1buffer to Hex string

1
  • What is hexagonal string? Did you mean hex string here? Please edit and clarify. Also, it is always helpful to give examples of input and expected output. Commented Dec 27, 2012 at 6:36

5 Answers 5

39

As you have mentioned c++, here is an answer. Iomanip is used to store ints in hex form into stringstream.

#include <iomanip>
#include <sstream>
#include <string>

std::string hexStr(const uint8_t *data, int len)
{
     std::stringstream ss;
     ss << std::hex;

     for( int i(0) ; i < len; ++i )
         ss << std::setw(2) << std::setfill('0') << (int)data[i];

     return ss.str();
}
Sign up to request clarification or add additional context in comments.

4 Comments

You need to pad with the '0' character using setfill('0').
I had also to add std::setw to have it works to output correctly 2 digit for each number. So now it looks like ss << std::hex << std:.setfill ('0'); and ss<<std::setw(2)<<static_cast<int>(data[i]);
This answer would be perfect if the comments were implemented.
But also, static_cast<uint32_t>(static_cast<uint8_t>(data[i])) to support negative numbers (char is signed on many platforms)
11

This code will convert byte array of fixed size 100 into hex string:

BYTE array[100];
char hexstr[201];
int i;
for (i=0; i<ARRAY_SIZE(array); i++) {
    sprintf(hexstr+i*2, "%02x", array[i]);
}
hexstr[i*2] = 0;

2 Comments

Thanks for answering but how should i return it. what variable should i return here ?
@AmitPal return something like std::string(hexstr)
10

Using stringstream, sprintf and other functions in the loop is simply not C++. It's horrible for performance and these kind of functions usually get called a lot (unless you're just writing some things into the log).

Here's one way of doing it. Writing directly into the std::string's buffer is discouraged because specific std::string implementation might behave differently and this will not work then but we're avoiding one copy of the whole buffer this way:

#include <iostream>
#include <string>
#include <vector>

std::string bytes_to_hex_string(const std::vector<uint8_t> &input)
{
  static const char characters[] = "0123456789ABCDEF";

  // Zeroes out the buffer unnecessarily, can't be avoided for std::string.
  std::string ret(input.size() * 2, 0);
  
  // Hack... Against the rules but avoids copying the whole buffer.
  auto buf = const_cast<char *>(ret.data());
  
  for (const auto &oneInputByte : input)
  {
    *buf++ = characters[oneInputByte >> 4];
    *buf++ = characters[oneInputByte & 0x0F];
  }
  return ret;
}

int main()
{
  std::vector<uint8_t> bytes = { 34, 123, 252, 0, 11, 52 };
  std::cout << "Bytes to hex string: " << bytes_to_hex_string(bytes) << std::endl;
}

2 Comments

This is much better than the expected solution. You can also remove the vector type input and use a pointer array instead. That'll make it even more minimal (requiring few libraries)
you can do this without violating the spec by using reserve and back_inserter std::string ret; ret.reserve(input.size() * 2); auto buf = std::back_inserter(ret);
9

Here is a somewhat more flexible version (Use uppercase characters? Insert spaces between bytes?) that can be used with plain arrays and various standard containers:

#include <string>
#include <sstream>
#include <iomanip>

template<typename TInputIter>
std::string make_hex_string(TInputIter first, TInputIter last, bool use_uppercase = true, bool insert_spaces = false)
{
    std::ostringstream ss;
    ss << std::hex << std::setfill('0');
    if (use_uppercase)
        ss << std::uppercase;
    while (first != last)
    {
        ss << std::setw(2) << static_cast<int>(*first++);
        if (insert_spaces && first != last)
            ss << " ";
    }
    return ss.str();
}

Example usage (plain array):

uint8_t byte_array[] = { 0xDE, 0xAD, 0xC0, 0xDE, 0x00, 0xFF };
auto from_array = make_hex_string(std::begin(byte_array), std::end(byte_array), true, true);
assert(from_array == "DE AD C0 DE 00 FF");

Example usage (std::vector):

// fill with values from the array above
std::vector<uint8_t> byte_vector(std::begin(byte_array), std::end(byte_array));
auto from_vector = make_hex_string(byte_vector.begin(), byte_vector.end(), false);
assert(from_vector == "deadc0de00ff");

Comments

2

how about using the boost library like this (snippet taken from http://theboostcpplibraries.com/boost.algorithm ):

#include <boost/algorithm/hex.hpp>
#include <vector>
#include <string>
#include <iterator>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::vector<char> v{'C', '+', '+'};
  hex(v, std::ostream_iterator<char>{std::cout, ""});
  std::cout << '\n';

  std::string s = "C++";
  std::cout << hex(s) << '\n';

  std::vector<char> w{'4', '3', '2', 'b', '2', 'b'};
  unhex(w, std::ostream_iterator<char>{std::cout, ""});
  std::cout << '\n';

  std::string t = "432b2b";
  std::cout << unhex(t) << '\n';
}

2 Comments

I'm not sure if you got downvoted because of Boost, but I think your answer is acceptable and should not have a negative score.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.