How do I convert this code to c++? - c++

I have this code:
string get_md5sum(unsigned char* md) {
char buf[MD5_DIGEST_LENGTH + MD5_DIGEST_LENGTH];
char *bptr;
bptr = buf;
for(int i = 0; i < MD5_DIGEST_LENGTH; i++) {
bptr += sprintf(bptr, "%02x", md[i]);
}
bptr += '\0';
string x(buf);
return x;
}
Unfortunately, this is some C combined with some C++. It does compile, but I don't like the printf and char*'s. I always thought this was not necessary in C++, and that there were other functions and classes to realize this. However, I don't completely understand what is going on with this:
bptr += sprintf(bptr, "%02x", md[i]);
And therefore I don't know how to convert it into C++. Can someone help me out with that?

sprintf returns number of bytes written. So this one writes to bptr two bytes (value of md[i] converted to %02x -> which means hex, padded on 2 chars with zeroes from left), and increases bptr by number of bytes written, so it points on string's (buf) end.
I don't get the bptr += '\0'; line, IMO it should be *bptr = '\0';
in C++ it should be written like this:
using namespace std;
stringstream buf;
for(int i = 0; i < MD5_DIGEST_LENGTH; i++)
{
buf << hex << setfill('0') << setw(2) << static_cast<int>(static_cast<unsigned char>(md[i]));
}
return buf.str();
EDIT: updated my c++ answer

bptr += sprintf(bptr, "%02x", md[i]);
This is printing the character in md[i] as 2 hex characters into the buffer and advancing the buffer pointer by 2. Thus the loop prints out the hex form of the MD5.
bptr += '\0';
That line is probably not doing what you want... its adding 0 to the pointer, giving you the same pointer back...
I'd implememt this something like this.
string get_md5sum(unsigned char* md) {
static const char[] hexdigits="0123456789ABCDEF";
char buf[ 2*MD5_DIGEST_LENGTH ];
for(int i = 0; i < MD5_DIGEST_LENGTH; i++) {
bptr[2*i+0] = hexdigits[ md[i] / 16 ];
bptr[2*i+1] = hexdigits[ md[i] % 16 ];
}
return string(buf,2*MD5_DIGEST_LENGTH );
}

I don't know C++, so without using pointers and strings and stuff, here's a (almost) pseudo-code for you :)
for(int i = 0; i < MD5_DIGEST_LENGTH; i++) {
buf[i*2] = hexdigits[(md[i] & 0xF0) >> 4];
buf[i*2 + 1] = hexdigits[md[i] & 0x0F];
}

Related

Store string as hex without converting

I have a string value:
string str = "2018";
Now I have to store in unsigned char array as hex representation but not really convert to hex:
unsigned char data [2]; //[0x20,0x18]
If I do it this way
data[0] = 0x20;
data[1] = 0x18;
It works, but my input is string, how I can resolve it?
Edit
If my input is unsigned char instead of string like
unsigned char y1 = 20;
unsigned char y2 = 18;
Is there any better way?.
A brief research made me find this function QString::toInt(bool&, int) which can be useful for your intent.
Basically you could:
if(str.size() % 2 == 1){
str = '0' + str;
}
for(int i = 0; i < str.size() / 2; i++){
data[i] = (str[2*i] + str[2*i+1]).toInt(res, 16);
}
I did not try this code, there surely a better way to extract the substring, and probably a more efficient way than to iterate over it.
Perhaps you could try something like this:
#include <iostream>
int main()
{
std::string s = "2018";
unsigned i;
std::sscanf(s.c_str(), "%04x", &i);
unsigned char data[2];
data[0] = i >> 8;
data[1] = i;
std::cout << std::hex << (int)data[0] << " " << (int)data[1] << std::endl;
return 0;
}
https://ideone.com/SyYKUl
Prints:
20 18
If you can assume the string to have 4 digits, you can convert it to BCD format simply and efficiently this way:
void convert_to_bcd4(unsigned char *data, const char *str) {
data[0] = (str[0] - '0') * 16 + (str[1] - '0');
data[1] = (str[2] - '0') * 16 + (str[3] - '0');
}
You can complete the conversion of "2018" to 0x20 0x18 using a hex string to binary converter. I think, for example, sscanf("%x",....) will do this. This typically gives an int. You can extract the byte values from the int in the normal way. (This method does not check for errors.)

Convert string to bytes in c++

I am new to c++ and still trying to feel my way in. I have attempted to adapt a function I have found on SO to convert my string into bytes as I need:
void hexconvert(const char *text, unsigned char bytes[])
{
int i;
int temp;
for (i = 0; i < 4; ++i) {
sscanf(text + 2 * i, "%2x", &temp);
bytes[i] = temp;
}
cout << bytes;
}
hexconvert("SKY 000.001\n", );
Issues I have are:
1) I am not sure how to amend the for loop to handle my string.
2) I am not sure what I should use as the input for the second parameter in the function.
Can anyone assist?
Thanks
This is my suggested solution. I used it to encode a GUID as a byte array. It should achieve higher performance than having to do printf on all the characters.
typedef unsigned char byte;
std::map<char, byte> char2hex =
{
{'0', 0x0},
{'1', 0x1},
{'2', 0x2},
{'3', 0x3},
{'4', 0x4},
{'5', 0x5},
{'6', 0x6},
{'7', 0x7},
{'8', 0x8},
{'9', 0x9},
{'a', 0xa},
{'b', 0xb},
{'c', 0xc},
{'d', 0xd},
{'e', 0xe},
{'f', 0xf}
};
void convertToBytes(const string &chars, byte bytes[])
{
for (size_t i = 0; i < chars.length() / 2; i++) {
byte b1 = (byte)(char2hex[chars[2*i]] << 4);
byte b2 = char2hex[chars[2*i+1]];
byte f = b1 | b2;
*(bytes + i) = f;
}
}
Remember that two ascii characters make up one byte, so for every pair of characters, I have to convert the first character to byte, then shift it up by 4 bits, then or it with the next character to get one byte.
To print a string as bytes:
const size_t length = data.length();
for (size_t i = 0; i < length; ++i)
{
unsigned int value = data[i];
std::cout << std::dec << std::fill(' ') << value
<< " (0x" << std::setw(2) << std::setfill('0') << std::hex << value << ')'
<< "\n";
}
Some important rules to remember:
1. Copy the character into an integer type variable, so that cout doesn't print as character.
2. Bytes are unsigned.
3. When filling the width with 0 for hex, remember to reset it to space before printing decimal.
4. Use std::hex for printing in hexadecimal, and remember to reset it with std::dec afterwards (if you are printing in decimal afterwards).
See <iomanip>.
Edit 1: C-Style
To use the C language style:
static const char data[] = "Hello World!";
const size_t length = strlen(data);
for (size_t i = 0; i < length; ++i)
{
printf("%3d (0x%02X)\n", data[i], data[i]);
}
The above assumes that data is a character array, nul terminated.

fgetc() reads 0c symbol and array elements are nullified? why is that?

I have noticed interesting thing but I am not sure if it is supposed to happen this way.
I got some code that uses fgetc(); to read symbols from file and store them into an int say l;
l=fgetc(file);
file is opened in read binary mode ("rb"); using
file=fopen("filename", "rb");
then using string stream each symbol is converted into hex format and sent into a string and then stored in a char array;
std::stringstream sl;
sl << std::hex << l; sl >> sll;
char as[i]=sll[i];
The problem is that when fgetc(); reads a symbol that in an ascii table is represented as OC in hex format or FF as char my final char array gets filled with 0's.
In short if char[] element contains 0c the rest of elements are 0's;
I have no idea why this happens. When I edited my file using hex editor and replaced 0c with something else. That file was read properly and all symbols got stored in an array as they were written in the file.
If you could tell how to circumvent such behaviors, I would appreciate that.
Ok. Full code:
#include <stdio.h>
#include<iostream>
#include <string.h>
#include "u.c"
#include <wchar.h>
#include <sstream>
int main() {
unsigned long F, K;
std::string k;
char hhh[300];
char hh1[300];
char kk[64];
int lk;
memset(kk, 0, 64);
FILE *diy;
FILE *ydi;
std::cin >> k;
std::cin >> hhh;
std::cin >> hh1;
lk = k.length();
for (int i = 0; i < lk; i++) {
kk[i] = k[i];
}
;
bof(kk, lk);
diy = fopen(hhh,"rb");
ydi = fopen(hh1,"wb");
int mm = 0;
int l;
int r;
char ll[9];
char rr[9];
memset(ll, 0, 9);
memset(rr, 0, 9);
std::string sll;
std::string slr;
char sL[3];
char sR[3];
int i = 0;
while (!feof(diy)) {
l = fgetc(diy);
r = fgetc(diy);
std::stringstream sl;
std::stringstream sr;
sl << std::hex << l;
sl >> sll;
sL[0] = sll[0];
sL[1] = sll[1];
sr << std::hex << r;
sr >> slr;
sR[0] = slr[0];
sR[1] = slr[1];
if (i == 0) {
ll[0] = sL[0];
ll[1] = sL[1];
ll[2] = sR[0];
ll[3] = sR[1];
sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';
}
;
if (i==1) {
ll[4] = sL[0];
ll[5] = sL[1];
ll[6] = sR[0];
ll[7] = sR[1];
sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';
}
;
if (i == 2) {
rr[0] = sL[0];
rr[1] = sL[1];
rr[2] = sR[0];
rr[3] = sR[1];
sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';
}
;
if(i==3){
rr[4] = sL[0];
rr[5] = sL[1];
rr[6] = sR[0];
rr[7] = sR[1];
sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';
}
;
sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';
if (i == 3) {
printf(" %s %s \n ", ll, rr); //indicated that my rr array had problems with that 0x0c;
sscanf(ll, "%08lX", &F);
sscanf(rr,"%08lX",&K);
printf(" before %08lx %08lx \n ", F, K);
omg( &F, &K);
printf(" after %20lx %20lx \n ", F, K);
memset(ll, 0, 9);
memset(rr, 0, 9);
char RR[9];
sprintf(RR, "%08lx", F);
char LL[9];
sprintf(LL, "%08lx", K);
printf(" %s %s ", LL, RR);
for (int j = 0; j < 4; j++) {
char ls[3];
ls[0] = LL[j*2];
ls[1] = LL[2*j+1];
int kj;
std::stringstream op;
op << ls;
op >> std::hex >> kj;
fputc(kj, ydi);
}
;
for(int j = 0; j < 4; j++) {
char lr[3];
lr[0] = RR[j*2];
lr[1] = RR[2*j+1];
int kjm;
std::stringstream ip;
ip << lr;
ip >> std::hex >> kjm;
fputc(kjm,ydi);
}
;
memset(LL, 0 ,9);
memset(RR, 0, 9);
}
;
i++;
std::cout << "\n";
if (i == 4) {
i = 0;
}
;
}
;
fclose(diy);
fclose(ydi);
}
;
Since you asked, now you have it.
this code will not compile because you do not have necessary libraries.
simplified code is at the beginning of this post.
those libraries that you do not posses have nothing to do with this issue.
The core problem
You assume that
std::stringstream the_stream;
std::string the_string;
the_stream << std::hex << 0x0C;
the_stream >> the_string;
results in the_string containing "0c". However, it will contain "c".
This means that later on, you end up converting the input "\x0c\xfe" to 'c', '\0', 'f', 'e'. If you use this at any point in a C-style string, of course it ends the string after c.
It was quite hard to debug this program. In the future, please write readable and understandable code. What follows is a non-exhaustive list of the problems I found.
Design problems
while(!feof(file)) is always wrong.
Use variable scoping. If you pull the declaration of sL and sR into the loop, you don't have to reset them. Less code, less potential errors.
You're using a lot of code for something as simple as converting a presumably 8-bit char to its hexadecimal representation. In fact, the only reason you ever use std::stringstream in your code is to do exactly that. Why don't you isolate this functionality to a function?
Irrelevant problems
Because of the poor code formatting, you probably didn't notice the copy-paste errors in the use of sL and sR:
sL[0] = '\0';
sR[0] = '\0';
sL[1] = '\0';
sL[1] = '\0';
Obviously, that last line should read sR[1] = '\0';
Style problems
There are many, many things wrong with your code, but one thing that easily stops people from helping is formatting. The space formatting in particular made your code very hard to read, so I took the liberty to edit the "full" code in your question to have (almost) consistent formatting. A few basic problems become evident:
Use meaningful names for variables and functions. I have no idea what you're trying to do here, which doesn't help in finding the real problem in the code.
Mixing <iostream> and <stdio.h> doesn't help the readability of your code. Choose one or the other. In fact, only ever use <iostream> in C++.
Besides that, use the appropriate header names for C++ (<cstring> and <cwchar> instead of <string.h> and <wchar.h>).
Don't write a semicolon after a compound statement. Instead of
int main(void) {
if (condition) {
one_statement();
another_statement();
};
};
you should write
int main(void) {
if (condition) {
one_statement();
another_statement();
}
}
The ; is part of a separate statement. It also prevents you from using else constructs.
Use initialisers where appropriate. So don't write
char ll[9];
char rr[9];
memset(ll, 0, 9);
memset(rr, 0, 9);
while
char ll[9] = { 0 };
char rr[9] = { 0 };
is more readable.
This 0c problem can be solved by :
changing char[] array where the value is stored to unsigned char[];
when the input is read with string stream this line is very helpfull
<< std::setfill('0') << std::setw(2) <<std::hex ;
When 0c is converted to c setw(); sets the width of a stream and setfill() pads it with 0's.

Conversion from Integer to BCD

I want to convert the integer (whose maximum value can reach to 99999999) in to BCD and store in to array of 4 characters.
Like for example:
Input is : 12345 (Integer)
Output should be = "00012345" in BCD which is stored in to array of 4 characters.
Here 0x00 0x01 0x23 0x45 stored in BCD format.
I tried in the below manner but didnt work
int decNum = 12345;
long aux;
aux = (long)decNum;
cout<<" aux = "<<aux<<endl;
char* str = (char*)& aux;
char output[4];
int len = 0;
int i = 3;
while (len < 8)
{
cout <<"str: " << len << " " << (int)str[len] << endl;
unsigned char temp = str[len]%10;
len++;
cout <<"str: " << len << " " << (int)str[len] << endl;
output[i] = ((str[len]) << 4) | temp;
i--;
len++;
}
Any help will be appreciated
str points actually to a long (probably 4 bytes), but the iteration accesses 8 bytes.
The operation str[len]%10 looks as if you are expecting digits, but there is only binary data. In addition I suspect that i gets negative.
First, don't use C-style casts (like (long)a or (char*)). They are a bad smell. Instead, learn and use C++ style casts (like static_cast<long>(a)), because they point out where you are doing things that are dangeruos, instead of just silently working and causing undefined behavior.
char* str = (char*)& aux; gives you a pointer to the bytes of aux -- it is actually char* str = reinterpret_cast<char*>(&aux);. It does not give you a traditional string with digits in it. sizeof(char) is 1, sizeof(long) is almost certainly 4, so there are only 4 valid bytes in your aux variable. You proceed to try to read 8 of them.
I doubt this is doing what you want it to do. If you want to print out a number into a string, you will have to run actual code, not just reinterpret bits in memory.
std::string s; std::stringstream ss; ss << aux; ss >> s; will create a std::string with the base-10 digits of aux in it.
Then you can look at the characters in s to build your BCD.
This is far from the fastest method, but it at least is close to your original approach.
First of all sorry about the C code, I was deceived since this started as a C questions, porting to C++ should not really be such a big deal.
If you really want it to be in a char array I'll do something like following code, I find useful to still leave the result in a little endian format so I can just cast it to an int for printing out, however that is not strictly necessary:
#include <stdio.h>
typedef struct
{
char value[4];
} BCD_Number;
BCD_Number bin2bcd(int bin_number);
int main(int args, char **argv)
{
BCD_Number bcd_result;
bcd_result = bin2bcd(12345678);
/* Assuming an int is 4 bytes */
printf("result=0x%08x\n", *((int *)bcd_result.value));
}
BCD_Number bin2bcd(int bin_number)
{
BCD_Number bcd_number;
for(int i = 0; i < sizeof(bcd_number.value); i++)
{
bcd_number.value[i] = bin_number % 10;
bin_number /= 10;
bcd_number.value[i] |= bin_number % 10 << 4;
bin_number /= 10;
}
return bcd_number;
}

C++: How to convert wstring with md5 hash to byte* array?

std::wstring hashStr(L"4727b105cf792b2d8ad20424ed83658c");
//....
byte digest[16];
How can I get my md5 hash in digest?
My answer is:
wchar_t * EndPtr;
for (int i = 0; i < 16; i++) {
std::wstring bt = hashStr.substr(i*2, 2);
digest[i] = static_cast<BYTE>(wcstoul(bt.c_str(), &EndPtr, 16));
}
You need to read two characters from hashStr, convert them from hex to a binary value, and put that value into the next spot in digest -- something on this order:
for (int i=0; i<16; i++) {
std::wstring byte = hashStr.substr(i*2, 2);
digest[i] = hextobin(byte);
}
C-way (I didn't test it, but it should work (though I could've screwed up somewhere) and you will get the method anyway).
memset(digest, 0, sizeof(digest));
for (int i = 0; i < 32; i++)
{
wchar_t numwc = hashStr[i];
BYTE numbt;
if (numwc >= L'0' && numwc <= L'9') //I assume that the string is right (i.e.: no SGJSGH chars and stuff) and is in uppercase (you can change that though)
{
numbt = (BYTE)(numwc - L'0');
}
else
{
numbt = 0xA + (BYTE)(numwc - L'A');
}
digest[i/2] += numbt*(2<<(4*((i+1)%2)));
}