c++stringhexbinary-dataprintf

Missing punctuation from C++ hex2bin


While trying to duplicate PHP's bin2hex($s) and pack('H*',$s) (aka hex2bin($s) in PHP 5.4.3+) in GCC/Linux C++, I seem to have it figured out except that it's dropping punctuation for some strange reason. Can you figure out what I might be doing wrong in the hex2bin() function? I compared PHP's bin2hex() with mine and it appears to be working there properly, so the problem is in hex2bin().

#include <strings.h>
#include <string>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

string bin2hex(string s) {
  int nLen = s.length();
  string sOut;
  char cBuff[2];
  for (int i = 0; i < nLen; i++) {
    sprintf(cBuff,"%.2x",s[i]);
    sOut.append(cBuff);
    cBuff[0] = '\0';
  }
  return sOut;
}

string hex2bin(string s) {
  int nLen = s.length();
  string sOut;
  char cBuff1[2];
  char cBuff2[2];
  char cBuff[1];
  int n,n1,n2;
  for (int i = 0; i <= nLen; i+=2) {
    sprintf(cBuff1,"%c",s[i]);
    sprintf(cBuff2,"%c",s[i+1]);
    n1 = atoi(cBuff1);
    n2 = atoi(cBuff2);
    n = (n1 * 16) + n2;
    sprintf(cBuff,"%c",n);
    sOut.append(cBuff);
    cBuff[0] = '\0';
    cBuff1[0] = '\0';
    cBuff2[0] = '\0';
  }
  return sOut;
}

int main() {
  string s;
  string sResult;  
  s = "This is a 123 test.";
  sResult = bin2hex(s);
  printf("ENCODED: %s\n",sResult.c_str());
  sResult = hex2bin(sResult);
  printf("UNENCODED: %s\n",sResult.c_str());
  return 1;
}

This emits:

ENCODED: 5468697320697320612031323320746573742e
UNENCODED: This is a 123 test

Solution

  • Okay, sleeves rolled up: let's look at C++ version:

    Live on Coliru

    #include <string>
    #include <sstream>
    #include <iomanip>
    
    std::string bin2hex(std::string const &s) {
        std::ostringstream oss;
    
        for (unsigned char ch : s)
            oss << std::hex << std::setw(2) << std::setfill('0') << (int) ch;
    
        return oss.str();
    }
    
    #include <cassert>
    std::string hex2bin(std::string const& s) {
        assert(s.length() % 2 == 0);
    
        std::string sOut;
        sOut.reserve(s.length()/2);
    
        std::string extract;
        for (std::string::const_iterator pos = s.begin(); pos<s.end(); pos += 2)
        {
            extract.assign(pos, pos+2);
            sOut.push_back(std::stoi(extract, nullptr, 16));
        }
        return sOut;
    }
    
    #include <iostream>
    int main() {
        std::cout << "ENCODED: " << bin2hex("This is a 123 test.")          << "\n";
        std::cout << "DECODED: " << hex2bin(bin2hex("This is a 123 test.")) << "\n";
    }
    

    Output:

    ENCODED: 5468697320697320612031323320746573742e
    DECODED: This is a 123 test.