In C++, I have an AES-encrypted char* which I transform to its HEX representation before sending it as an URL parameter, just as it is done in this question. Now, I want to do the opposite, that is converting such hex back to char* again. However I am puzzled here - using the sprintf with either %x or %s would result in a totally different value. How could I convert it back again? Thanks...
You can use sscanf() like this:
#define LEN 16 /* 128/8 */
void aes_to_char(char *aes, char *res)
{
int i;
for (i = 0; i < LEN; i++) {
sscanf(aes, "%2hhx", &res[i]);
aes += 2;
}
}
"%2hhx" means "a 2-chars hexadecimal value, to be stored in a char *.
Related
I have a function definition like this in an Arduino library:
bool RHReliableDatagram::sendtoWait(uint8_t * buf, uint8_t len, uint8_t address)
When I use:
uint8_t timePacket[] = "time\n";
sendtoWait(timePacket, sizeof(timePacket), SERVER_ADDRESS)
I get a perfectly fine string with "time" at the other end (SERVER_ADDRESS) in pyserial's readline() function which is decoded perfectly using utf-8 encoding.
Now I need to send some bytes using the same sendtoWait() function. I first define a char array of 60 bytes
char packetBuff[60] = "";
Then I get every byte and cast it as a char
char value = (char)flash.readByte(dumpCounter++);
Then put each value in the char array like this:
packetBuff[charNo] = value;
After I find a new line character I try to send the char array again using the sendtoWait() function:
if (value == '\n') {
Serial.println(packetBuff);
uint8_t buff[charNo];
for (int i = 0; i < charNo; i++) {
buff[i] = packetBuff[i];
}
sendtoWait(buff, charNo, SERVER_ADDRESS))
charNo++;
But although Serial.println(packetBuff) shows the proper characters e.g. something like "1559105487\n" (unix timestamp), buff array is just not working correctly and shows random characters something like a semi-colon, random single digit numbers etc.
How do I properly cast the char array and send it properly using the sendtoWait() function like "time\n" was sent?
EDIT:
Full code:
int charNo = 0;
char packetBuff[60] = "";
if (dumpCounter != 0) {
dumpCounter--;
}
while(dumpCounter < currentFlashLoc) {
char value = (char)flash.readByte(dumpCounter++);
packetBuff[charNo] = value;
if (value == '\n') {
Serial.println(packetBuff);
uint8_t buff[charNo];
for (int i = 0; i < charNo; i++) {
buff[i] = packetBuff[i];
}
if (manager.sendtoWait(buff, charNo, SERVER_ADDRESS)) {
// packet sent successfully
}
charNo = -1;
}
charNo++;
}
Casting the char array like this:
sendtoWait((uint8_t*)packetBuff, sizeof(packetBuff), SERVER_ADDRESS)
works correctly. buff is not required.
I am trying to take the sensor data from Arduino & Raspberry Pi using RS232 serial communication. I have searched for this small thing and found something related on this below link but was unable get the full idea.
The os (kernel) has an internal buffer of 4096 bytes. If this buffer is full and a new character arrives on the serial port, the oldest character in the buffer will be overwritten and thus will be lost. After a successful call to RS232_OpenComport(), the os will start to buffer incoming characters.
The values are properly coming from Arduino to Raspberry Pi (output attached below) and it is storing in a pointer to unsigned char[] which is defined as unsigned char *buf[4096].
int main()
{
int i, n,
cport_nr=0, /* /dev/ttyS0 (COM1 on windows) */
bdrate=9600; /* 9600 baud */
unsigned char buf[4096];
char mode[]={'8','N','1',0};
while(1)
{
n = RS232_PollComport(cport_nr, buf, 4095);
if(n > 0)
{
buf[n] = 0;
for(i=0; i < n; i++)
{
if(buf[i] < 32) /* replace unreadable control-codes by dots */
{
buf[i] = '.';
}
}
printf("received %i bytes: %s\n", n, (char *)buf);
}
}
Now I want to store these values in another float/double variable so that I can perform further operations on it. How to store a value suppose 0.01 to a float/double which is later used to create stuff.
From the output in the screenshot it looks like you are sending the string representation of the numbers rather than the actual numbers. You just need to detect those "unreadable control-codes" that you are just replacing with a . as they will probably tell you when a number ends and another begins. Just make QSerialPort * serial; a proper class member.
Also, check for errors on opening the port: serial->open(QIODevice::ReadWrite); Then, insert some qDebug() in serialreceived() to see if the slot is called at all and if the canReadLine() works. you should use QByteArray to read your data. If there's any char in the response, that is not String conform, the resulting QString will be prematurely terminated, use readLine() instead readAll() like this:
QByteArray data = serial -> readLine();
qDebug() < data.toHex(' '); // prints the hex representation of your char array
QString str(data);
qDebug() << str;
First, it will be better if you use some other ASCII character (e.g. space) to separate the numbers, because . dot is a part of floating point number. Then, you can construct std::string object from your raw unsigned char array, split it in a multiple strings and convert each string to float.
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
int main() {
// imagine that this buff is already after read and preprocessing
unsigned char buff[1024] = "13.60 13.60 -11.12 -0.3 and let's say that the rest is garbage";
int n = 28; // let's say that you received 28 bytes
std::string strBuff(reinterpret_cast<char*>(buff), n); // construct a string from buff using just first 28 bytes
std::vector<std::string> numbers;
boost::split(numbers, strBuff, boost::is_any_of(" "), boost::token_compress_on);
for (const auto& n : numbers) {
try {
std::cout << std::stof(n) << std::endl;
} catch (const std::exception& e) {
std::cout << n << " is not convertible to float: " << e.what() << std::endl;
}
}
return 0;
}
I took the string splitting method from this answer but you can use anything that works for you.
I used reinterpret_cast because std::string accepts char instead of unsigned char as a CTor arg.
I have an Arduino that controls timers. The settings for timers are stored in byte arrays. I need to convert the arrays to strings to SET a string on an external Redis server.
So, I have many arrays of bytes of different lengths that I need to convert to strings to pass as arguments to a function expecting char[]. I need the values to be separated by commas and terminated with '\0'.
byte timer[4] {1,5,23,120};
byte timer2[6] {0,0,0,0,0,0}
I have succeeded to do it manually for each array using sprintf() like this
char buf[30];
for (int i=0;i<5;i++){ buf[i] = (int) timer[i]; }
sprintf(buf, "%d,%d,%d,%d,%d",timer[0],timer[1],timer[2],timer[3],timer[4]);
That gives me an output string buf: 1,5,23,120
But I have to use a fixed number of 'placeholders' in sprintf().
I would like to come up with a function to which I could pass the name of the array (e.g. timer[]) and that would build a string, probably using a for loop of 'variable lengths' (depending of the particular array to to 'process') and many strcat() functions. I have tried a few ways to do this, none of them making sense to the compiler, nor to me!
Which way should I go looking?
Here is the low tech way you could do it in normal C.
char* toString(byte* bytes, int nbytes)
{
// Has to be static so it doesn't go out of scope at the end of the call.
// You could dynamically allocate memory based on nbytes.
// Size of 128 is arbitrary - pick something you know is big enough.
static char buffer[128];
char* bp = buffer;
*bp = 0; // means return will be valid even if nbytes is 0.
for(int i = 0; i < nbytes; i++)
{
if (i > 0) {
*bp = ','; bp++;
}
// sprintf can have errors, so probably want to check for a +ve
// result.
bp += sprintf(bp, "%d", bytes[i])
}
return buffer;
}
an implementation, assuming that timer is an array (else, size would have to be passed as a parameter) with the special handling of the comma.
Basically, print the integer in a temp buffer, then concatenate to the final buffer. Pepper with commas where needed.
The size of the output buffer isn't tested, mind.
#include <stdio.h>
#include <strings.h>
typedef unsigned char byte;
int main()
{
byte timer[4] = {1,5,23,120};
int i;
char buf[30] = "";
int first_item = 1;
for (i=0;i<sizeof(timer)/sizeof(timer[0]);i++)
{
char t[10];
if (!first_item)
{
strcat(buf,",");
}
first_item = 0;
sprintf(t,"%d",timer[i]);
strcat(buf,t);
}
printf(buf);
}
tl;dr
Why do I get different output every time I run this code (Ideone):
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
const char* _user = "FOO";
const char* _password = "BAR";
char login[21];
sprintf(login,
"\x15\x00\x01%-8s%-10s",
_user,
_password);
for (int i = 0; i < 21; i++) {
printf(" %02x", login[i] & 0xff);
}
return 0;
}
But not this code (Ideone):
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
const char* _user = "FOO";
const char* _password = "BAR";
const char* _session = "ABCDEFGHIJ";
int _expectedSeq = 123;
char login[38];
sprintf(login,
"L%-6s%-10s%10s%10d\xA",
_user,
_password,
_session,
_expectedSeq);
for (int i = 0; i < 38; i++) {
printf(" %02x", login[i] & 0xff);
}
return 0;
}
Question
Deep in our application code, I came across this:
char login[38];
sprintf(login,
"L%-6s%-10s%10s%10d\xA",
_user,
_password,
_session,
_expectedSeq);
Now, I need to write a (simpler) variant of this code:
char login[21];
sprintf(login,
"\x15\x00\x01%-8s%-10s",
_user,
_password);
Somehow, this doesn't work! What's weird is that the latter produces different results every time.
Thoughts
The former example only has a hex literal at the end. Is this masking the issue in the former's case?
Or, am I actually messing up my debug output, printf? (By the way, I got the & 0xff thing from Printing hexadecimal characters in C.)
Could it have something to do with using char instead of unsigned char? But then, why does the former case work?
The problem is that your string literal has an embedded NUL byte, and that marks the end of the string as far as sprintf is concerned. So your call is identical to:
sprintf(login,
"\x15",
_user,
_password);
And that writes into the login array only two bytes: 0x15 0x00.
There are several approaches to solve this mixing of bytes and characters. My choice would be something along the lines of:
memcpy(login, "\x15\x00\x01", 3);
sprintf(login + 3,
"%-8s%-10s",
_user,
_password);
The call to memcpy takes as parameter the number of bytes, so it is immune to the embedded NUL problem.
But note that sprintf automaticall adds a NUL byte at the end of the output string, so you actually need 22 bytes: 3 + 8 + 10 + 1 = 22:
char login[22];
Your issue is that second format string contains a null character (\x00) which terminates it prematurely. Change the string to use %c instead and have a null character printed there.
I have created a function to count the byte length of an incoming hex string, then convert that length into hexidecimal. It first assigns the Byte Length of the incoming string to an int, then I convert the int to a string. After assigning the byte length of my incoming string to an int, I check to see if it is more than 255, if it is, I insert a zero so that I have 2 bytes returned, instead of 3-bits.
I do the follwing:
1) Takes in the Hex string and divides the number by 2.
static int ByteLen(std::string sHexStr)
{
return (sHexStr.length() / 2);
}
2) Takes in Hex string, then converts to a Hex format string with itoa()
static std::string ByteLenStr(std::string sHexStr)
{
//Assign the length to an int
int iLen = ByteLen(sHexStr);
std::string sTemp = "";
std::string sZero = "0";
std::string sLen = "";
char buffer [1000];
if (iLen > 255)
{
//returns the number passed converted to hex base-16
//if it is over 255 then it will insert a 0 infront
//so to have 2 bytes instead of 3-bits
sTemp = itoa (iLen,buffer,16);
sLen = sTemp.insert(0,sZero);
return sLen;
}
else{
return itoa (iLen,buffer,16);
}
}
I convert the length to hexidecimal. This seems to work fine, however I am looking for maybe a more simpler way to format the text like I would in C# with the ToString("X2") method. Is this it for C++ or does my method work well enough?
Here is how I would do it in C#:
public static int ByteLen(string sHexStr)
{
return (sHexStr.Length / 2);
}
public static string ByteLenStr(string sHexStr)
{
int iLen = ByteLen(sHexStr);
if (iLen > 255)
return iLen.ToString("X4");
else
return iLen.ToString("X2");
}
My logic may be off a bit in C++, but the C# method is good enough for me in what I want to do.
Thank you for your time.
static std::string ByteLenStr(std::string& sHexStr)
{
int iLen = ByteLen(sHexStr);
char buffer[16];
snprintf(buffer, sizeof(buffer), (iLen > 255) ? "%04x" : "%02x", iLen);
return buffer;
}
snprintf formats text in a buffer using a format string and a variable list of arguments. We are using the %x format code to convert a int argument into a hex string. In this instance, we have two format strings to choose from:
When iLen > 255, we want the number to be four digits long. %04x means format as a hex string, with zero-padding at the beginning up to four places.
Otherwise, we want the number to be two digits long. %02x means format as a hex string, with zero-padding up to two places.
We use the ternary operator to select which format string we use. Finally, iLen is passed as the single argument which will be used to provide the value that is formatted by the function.
For a purely C++ solutuon that does not use any C functions, try using a std::stringstream to help you with formatting:
static std::string ByteLenStr(std::string sHexStr)
{
//Assign the length to an int
int iLen = ByteLen(sHexStr);
//return the number converted to hex base-16
//if it is over 255 then insert a 0 in front
//so to have 2 bytes instead of 3-bits
std::stringstream ss;
ss.fill('0');
ss.width((iLen > 255) ? 4 : 2);
ss << std::right << std::hex << iLen;
return ss.str();
}