I am searching a way to convert hex char to bytes like \x90\x0d\x41 and when I use printf(), binary data are printed?
char *hex = "909090904241";
when I need to get \x90\x90\x90\x90\x42\x42 and when I print I get binary data.
int hex_to_bytes(const char* hex, uint8_t** buf_ptr, size_t** len_ptr) {
size_t len = strlen(hex);
if (len % 2)
goto error1;
len /= 2;
char* buf = malloc(len);
char hex_byte[3];
hex_byte[2] = 0;
for (size_t i=len; i--; ) {
hex_byte[0] = *(hex++);
hex_byte[1] = *(hex++);
char* end_ptr;
buf[i] = strtoul(hex_byte, &end_ptr, 16);
if (end_ptr != hex_byte+2)
goto error2;
}
*buf_ptr = buf;
*len_ptr = len;
return 1;
error2:
free(buf);
error1:
*buf_ptr = NULL;
*len_ptr = 0;
return 0;
}
uint8_t* buf;
size_t len;
if (!hex_to_bytes(hex, &buf, &len)) {
... handle error ...
}
... Use buf and len ...
free(buf);
Notes that buf isn't nul-terminated. I didn't see the point of making it nul-terminated string when the input could be "000000".
For each character in the string, first convert it to a number by subtracting its ASCII by either the character '0' or 'A'. Then assign each value into the target array, shifting as necessary.
The below assumes ASCII, and that the input string contains only characters in the range 0-9 and A-F.
char *str="909090904241";
unsigned char a[strlen(str)/2+1] = {0};
int i;
for (i=0;i<strlen(str);i++) {
unsigned char num = (str[i] >= '0' && str[i] <= '9') ? str[i] - '0' : str[i] - 'A' + 10;
a[i/2] |= num << (4 * (1 - (i % 2))); // shift even index bits by 4, odd index by 0
}
for (i=0;i<strlen(str)/2+1;i++) {
printf("%02x ", a[i]);
}
printf("\n");
Output:
90 90 90 90 42 41
so basically I have a variable which contains hex bytes and when I print them I obtain binary representation
#include<stdio.h>
char *hex_bytes = "\x90\x90\x90\x41";
int main () {
printf(hex_bytes);
return 0 ;
}
I wanna do the same with hex chars like that
char *hex = "9090904241";
Thank you , HM
Loop through the string and append to a new string a piece with \x added infront like this:
const char *hex = "909090904241";
char* result = malloc((strlen(hex) * 2 + 1)* sizeof(char));
result[0] = 0;
char piece[] = "\\x00";
for (int i = 0; i < strlen(hex); i+=2) {
piece[2] = hex[i];
piece[3] = hex[i+1];
strcat(result, piece);
}
Related
I'm trying to write() hexadecimal representation of \n without any success.
The code I have ft_putstr_non_printable.c:
#include <unistd.h>
void ft_putstr_non_printable(char *str)
{
int i;
unsigned char a;
char c;
i = 0;
a = 0x0;
while (str[i] != '\0')
{
if (str[i] <= 31 || str[i] == 127)
{
a = str[i];
write(1, &a, 1);
}
else
{
c = str[i];
write(1, &c, 1);
}
i++;
}
}
And main.c:
#include <stdio.h>
#include <string.h>
#include "ft_putstr_non_printable.c"
int main(void)
{
char a[] = "\n au revoir\a";
char b[] = "omellette du fromage\b";
char c[] = "coeuf#ca6va\e fef";
char d[] = " Batata \x7F rfg";
char e[] = "roquefort`[e{forte-e_tem,bolor \n feff";
char f[] = " we 9are 78familly \x1F rgfenf";
ft_putstr_non_printable(a);
ft_putstr_non_printable(b);
ft_putstr_non_printable(c);
ft_putstr_non_printable(d);
ft_putstr_non_printable(e);
ft_putstr_non_printable(f);
}
Am I doing something wrong? How do I get \x0a?
Edit: I can't use printf(). I'm limited to write().
Instead writing one character when str[i] is out of the printable range, form a little string and write that.
// if (str[i] <= 31 || str[i] == 127)
if (str[i] <= 31 || str[i] >= 127) {
unsigned char a = str[i];
char buf[5];
int len = sprintf(buf, "\\x%02X", a);
// write(1, &a, 1);
write(1, buf, len);
}
I'm limited to write()
If sprintf() not available:
// int len = sprintf(buf, "\\x%02X", a);
buf[0] = '\\';
buf[1] = 'x';
buf[2] = "0123456789ABCDEF"[a/16];
buf[3] = "0123456789ABCDEF"[a%16];
buf[4] = '\0';
len = 4;
Advanced:
char may be unsigned, so values above 127 are possible.
To well reverse the process it might make sense to print the \\ in hex.
if (str[i] <= 31 || str[i] >= 127 || str[i] == '\\') {
Notice:
I recommend the answer from chux - Reinstate Monica due to the nice conversion from 0..15 to hex.
See https://stackoverflow.com/a/68307913/4386427
I'll leave this answer as-is just in case someone should prefer this code-wise longer way of doing the conversion
Answer
Given all your restriction (which prevents normal code), you may be looking for:
char a = '\n'; // Or any other char
char h;
unsigned char tmp;
tmp = a;
tmp = tmp / 16;
if (tmp < 10)
{
h = '0' + tmp;
}
else
{
h = 'a' + tmp - 10;
}
write(1,&h,1);
tmp = a
tmp = tmp % 16;
if (tmp < 10)
{
h = '0' + tmp;
}
else
{
h = 'a' + tmp - 10;
}
write(1,&h,1);
Output
0a
Yet another option:
void ft_putstr_non_printable(const char *str) {
static const char hex[] = "0123456789ABCDEF";
int outfd = fileno(stdout);
char buf[4] = {'0', 'x'};
unsigned char ch; // used to convert the usually signed `char` to unsigned
for(; (ch = *str) != '\0'; ++str) { // loop until null terminator
if (ch < ' ' || ch > '~') { // outside printable ASCII range?
// pick the last two chars in `buf` from the hex array:
buf[2] = hex[ch >> 4]; // the high nibble
buf[3] = hex[ch & 0xF]; // the low nibble
write(outfd, buf, sizeof buf); // ex: writes 0x7F if ch == 127
} else {
write(outfd, &ch, 1);
}
}
ch = '\n';
write(outfd, &ch, 1);
}
I have wrapped the hex output into [] to make them mo distinct.
#include <unistd.h>
void ft_putstr_non_printable(const char *s)
{
const char *hex = "0123456789ABCDEF";
const unsigned char *str = s;
while (*str)
{
if (*str <= 31 || *str >= 127)
{
char hexrep[] = {'[','0','x', hex[*str >> 4], hex[*str & 0x0f],']'};
write(1, hexrep, sizeof(hexrep));
}
else
{
write(1, str, 1);
}
str++;
}
write(1, (char[]){'\n'},1);
}
int main(void)
{
char a[] = "\n au revoir\a";
char b[] = "omellette du fromage\b";
char c[] = "coeuf#ca6va\e fef";
char d[] = " Batata \x7F rfg";
char e[] = "roquefort`[e{forte-e_tem,bolor \n feff";
char f[] = " we 9are 78familly \x1F rgfenf";
ft_putstr_non_printable(a);
ft_putstr_non_printable(b);
ft_putstr_non_printable(c);
ft_putstr_non_printable(d);
ft_putstr_non_printable(e);
ft_putstr_non_printable(f);
}
https://godbolt.org/z/zq7sPfM6q
Output:
[0x0A] au revoir[0x07]
omellette du fromage[0x08]
coeuf#ca6va[0x1B] fef
Batata [0x7F] rfg
roquefort`[e{forte-e_tem,bolor [0x0A] feff
we 9are 78familly [0x1F] rgfenf
If you want to have \xHH format suimply change one line to:
char hexrep[] = {'\\','x', hex[*str >> 4], hex[*str & 0x0f]};
https://godbolt.org/z/6GonenfK7
Output:
\x0A au revoir\x07
omellette du fromage\x08
coeuf#ca6va\x1B fef
Batata \x7F rfg
roquefort`[e{forte-e_tem,bolor \x0A feff
we 9are 78familly \x1F rgfenf
What does write() actually do? It's defined in <unistd.h> as:
ssize_t write(int fildes, const void *buf, size_t nbyte);
It writes to a filedescriptor. It writes from a buffer and writes nbytes bytes from that memory location.
Thus when you pass &i to it, write just sees memory addresses. It doesn't see an int. Likewise with &c. What you need to do is turn each character (as a number) into a string representing the character. The code for ft_putstr_non_printable would look something like:
void ft_putstr_non_printable(char *str)
{
int i;
unsigned char a;
i = 0;
const char[] hexchars = "0123456789ABCDEF";
for (int ii = 0;str[i]!='\0';ii++)
{
a = str[i];
if (str[i]> 31 && str[i] < 127)
write(1, &a, 1);
else
{
write(1,'[',1);
if (a<=16
while (a!=0)
{
write(1,hexchars+(a%16),1);
a/=16;
}
write(1,']',1);
}
}
}
This is basically how itoa() works. #4386427's answer is more elegant for single byte characters, but I wanted to explicitly show how one would do it in a while loop.
Taking an input as hex string and then converting it to char string in C. The hex string can contain 0x00 which translates to an 0 in Ascii when converted. This terminates the string. I have to store the value in an char string because the API uses that.
My code so far:
int hex_to_int(unsigned char c) {
int first =0;
int second =0;
int result=0;
if(c>=97 && c<=102)
c-=32;
first=c / 16 - 3;
second =c % 16;
result = first*10 + second;
if(result > 9) result--;
return result;
}
unsigned char hex_to_ascii(unsigned char c, unsigned char d){
unsigned char a='0';
int high = hex_to_int(c) * 16;
int low = hex_to_int(d);
a= high+low;
return a;
}
unsigned char* HextoString(unsigned char *st){
int length = strlen((const char*)st);
unsigned char* result=(unsigned char*)malloc(length/2+1);
unsigned char arr[500];
int i;
unsigned char buf = 0;
int j=0;
for(i = 0; i < length; i++)
{
if(i % 2 != 0)
{
arr[j++]=(unsigned char)hex_to_ascii(buf, st[i]);
}
else
{
buf = st[i];
}
}
arr[length/2+1]='\0';
memcpy(result,arr,length/2+1);
return result;
}
You can store any values in a char array. But if you want to store a value of 0x00, you cannot use the string functions on this array. So you have to use an integer variable to store the length of the data you want to store. You can then write functions that use this integer.
As you provided more information now, I can tell you that your function doesn't cut anything as it loops through the whole C-string which you provided for example as input "0a12345600a0020b12". The "problem" is that if you want to get the length (strlen()) of the output string after the conversion for example then it will stop at '\0' and you will get a "wrong" length in terms of your original input string.
It is exacly like it's written in the answer of Xaver save the length information and the string to work with that length and not the one you would get by the C-string functions like strlen().
To show that and in order to provide a right length information I've added a struct definition to your code that defines a string type consisting of a size_t len and an unsigned char* str called HexString. With the additional length information you can handle a 0 byte. Also I made little changes to your code, e.g. you don't need that character buffer arr on the stack.
With your input: "0a12345600a0020b12"
the following output you will see: <0a> <12> <34> <56> <00> <a0> <02> <0b> <12> <00>
if you print the C-string hexadecimal every single character. The last <00> is the null termination.
Look here on ideone for a live example.
The code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
size_t len; /* C-string length + '\0' */
unsigned char* str;
} HexString;
int hex_to_int(unsigned char c)
{
int first =0;
int second =0;
int result=0;
if (c >= 97 && c <= 102) /* 97 = 'a'; 102 = 'f' */
c -= 32;
first = c / 16 - 3;
second = c % 16;
result = first * 10 + second;
if (result > 9) result--;
return result;
}
unsigned char hex_to_ascii(unsigned char c, unsigned char d)
{
unsigned char a = '0';
int high = hex_to_int(c) * 16;
int low = hex_to_int(d);
a = high + low;
return a;
}
HexString HextoString(const char* const st)
{
HexString result;
size_t length = strlen(st);
result.len = length/2+1;
result.str = malloc(length/2+1);
size_t i;
size_t j = 0;
unsigned char buf = 0;
for (i = 0; i < length; i++)
{
if (i % 2 != 0)
{
result.str[j++] = hex_to_ascii(buf, st[i]);
}
else
{
buf = (unsigned char)st[i];
}
}
result.str[length/2+1] = '\0';
return result;
}
int main()
{
size_t i;
HexString hexString = HextoString("0a12345600a0020b12");
for (i = 0; i < hexString.len; ++i)
{
printf("<%02x> ", hexString.str[i]);
}
free(hexString.str);
return 0;
}
I'm making a char array binary representations of a number. I want to terminate the end of the string with '\0'. It prints the array find aside from the intended garbage value.
However when I try to terminate the array, specifically the index of the garbage value, it won't print out my string.
int main(void)
{
char s[8] = {0};
printing_binary(s, 8, 2);
}
void printing_binary(char *s, int length, unsigned n){
for(int i = 0; i < length; i++){
if(1 & (n >> i)){
s[i] = '1';
}
else{
s[i] = '0';
}
}
//Trying to terminate my string
//s[length] = '\0';
printf(s);
}
This code will print out something like 01000000}.
However if I uncomment out s[length] = '\0', it prints nothing/the program stops executing. I've tried printing out "Hello world" after everything.
If you define your result array as char s[8], then you must not write anything at position 8 like in s[length] = 0x0 with length==8, because this exceeds the array length. Try:
char s[9] = {0};
printing_binary(s, (9-1), 2);
You have an 8 bit length which you fill up with the values. For example the value 2 is 00000010 Since you have filled up your string array, you have no room for the ending character. If you define the array size as length+1, then it will work.
int main(void)
{
char s[9] = {0}; // Note size is length+1
printing_binary(s, 8, 2);
}
void printing_binary(char *s, int length, unsigned n){
for(int i = 0; i < length; i++){
if(1 & (n >> i)){
s[i] = '1';
}
else{
s[i] = '0';
}
}
//Trying to terminate my string
s[length] = '\0'; // s must be an array of size greater than length
printf(s);
}
If you don't want to add a null terminator, you just have t modify the printf slightly.
int main(void)
{
char s[8] = {0};
printing_binary(s, 8, 2);
}
void printing_binary(char *s, int length, unsigned n){
for(int i = 0; i < length; i++){
if(1 & (n >> i)){
s[i] = '1';
}
else{
s[i] = '0';
}
}
//Trying to terminate my string
//s[length] = '\0';
printf("%.*s", length, s);
}
Another way is to declare i outside the loop. This can be useful if for some reason your logic breaks out of the loop before reaching length
int i;
for ( i=0; i < length; i++ ) {
...
}
s[i] = '\0';
I'm having the literal value that should be stored on an unsigned char[64] array. How can I convert such values to it's hex equivalent?
int main() {
unsigned char arry[1] = { 0xaa }
char* str = "fe"; //I want to store 0xfe on arry[0]
arry[0] = 0xfe; // this works, but I have to type it
arry[0] = 0x + str; //obviously fails
return 0;
}
Any pointers?
arr[0] = strtol(str,NULL,16); // If one entry is big enough to hold it.
For each character c, the value is:
if ('0' <= c && c <= '9') return c - '0';
if ('a' <= c && c <= 'f') return c - 'a' + 10;
if ('A' <= c && c <= 'F') return c - 'A' + 10;
// else error, invalid digit character
Now just iterate over the string from left to right, adding up the digit values, and multiplying the result by 16 each time.
(This is implemented for you by the standard library in the strto*l functions with base 16.)
Use function strtol() to convert a string to a long in a specific base: http://www.cplusplus.com/reference/cstdlib/strtol/
"Parses the C-string str interpreting its content as an integral number of the specified base, which is returned as a long int value. If endptr is not a null pointer, the function also sets the value of endptr to point to the first character after the number."
Example:
#include <stdio.h> /* printf */
#include <stdlib.h> /* strtol */
int main ()
{
char szNumbers[] = "2001 60c0c0 -1101110100110100100000 0x6fffff";
char * pEnd;
long int li1, li2, li3, li4;
li1 = strtol (szNumbers,&pEnd,10);
li2 = strtol (pEnd,&pEnd,16);
li3 = strtol (pEnd,&pEnd,2);
li4 = strtol (pEnd,NULL,0);
printf ("The decimal equivalents are: %ld, %ld, %ld and %ld.\n", li1, li2, li3, li4);
return 0;
}
Put together an arbitrary length solution to and from.
Sadly the String to X is verbose: pesky dealing with non hex string, odd length, too big, etc.
#include <string.h>
#include <stdio.h>
// S assumed to be long enough.
// X is little endian
void BigXToString(const unsigned char *X, size_t Length, char *S) {
size_t i;
for (i = Length; i-- > 0; ) {
sprintf(S, "%02X", X[i]);
S += 2;
}
}
int BigStringToX(const char *S, unsigned char X[], size_t Length) {
size_t i;
size_t ls = strlen(S);
if (ls > (Length * 2)) {
return 1; //fail, too big
}
int flag = ls & 1;
size_t Unused = Length - (ls/2) - flag;
memset(&X[Length - Unused], 0, Unused); // 0 fill unused
char little[3];
little[2] = '\0';
for (i = Length - Unused; i-- > 0;) {
little[0] = *S++;
little[1] = flag ? '\0' : *S++;
flag = 0;
char *endptr;
X[i] = (unsigned char) strtol(little, &endptr, 16);
if (*endptr) return 1; // non-hex found
if (*S == '\0') break;
}
return 0;
}
int main() {
unsigned char X[64];
char S[64 * 2 + 2];
char T[64 * 2 + 2];
strcpy(S, "12345");
BigStringToX(S, X, sizeof(X));
BigXToString(X, sizeof(X), T);
printf("'%s'\n", T);
return 0;
}
I need to convert a string, containing hex values as characters, into a byte array. Although this has been answered already here as the first answer, I get the following error:
warning: ISO C90 does not support the ‘hh’ gnu_scanf length modifier [-Wformat]
Since I do not like warnings, and the omission of hh just creates another warning
warning: format ‘%x’ expects argument of type ‘unsigned int *’, but argument 3 has type ‘unsigned char *’ [-Wformat]
my question is: How to do this right? For completion, I post the example code here again:
#include <stdio.h>
int main(int argc, char **argv)
{
const char hexstring[] = "deadbeef10203040b00b1e50", *pos = hexstring;
unsigned char val[12];
size_t count = 0;
/* WARNING: no sanitization or error-checking whatsoever */
for(count = 0; count < sizeof(val)/sizeof(val[0]); count++) {
sscanf(pos, "%2hhx", &val[count]);
pos += 2 * sizeof(char);
}
printf("0x");
for(count = 0; count < sizeof(val)/sizeof(val[0]); count++)
printf("%02x", val[count]);
printf("\n");
return(0);
}
You can use strtol() instead.
Simply replace this line:
sscanf(pos, "%2hhx", &val[count]);
with:
char buf[10];
sprintf(buf, "0x%c%c", pos[0], pos[1]);
val[count] = strtol(buf, NULL, 0);
UPDATE: You can avoid using sprintf() using this snippet instead:
char buf[5] = {"0", "x", pos[0], pos[1], 0};
val[count] = strtol(buf, NULL, 0);
You can either switch your compiler to C99 mode (the hh length modifier was standardised in C99), or you can use an unsigned int temporary variable:
unsigned int byteval;
if (sscanf(pos, "%2x", &byteval) != 1)
{
/* format error */
}
val[count] = byteval;
Why not do it without using sscanf, strol, etc. Below is HexToBin and as a free-bee, BinToHex. (Note originally there were returned enum error codes through an error logging system not a simple -1 return.)
unsigned char HexChar (char c)
{
if ('0' <= c && c <= '9') return (unsigned char)(c - '0');
if ('A' <= c && c <= 'F') return (unsigned char)(c - 'A' + 10);
if ('a' <= c && c <= 'f') return (unsigned char)(c - 'a' + 10);
return 0xFF;
}
int HexToBin (const char* s, unsigned char * buff, int length)
{
int result;
if (!s || !buff || length <= 0) return -1;
for (result = 0; *s; ++result)
{
unsigned char msn = HexChar(*s++);
if (msn == 0xFF) return -1;
unsigned char lsn = HexChar(*s++);
if (lsn == 0xFF) return -1;
unsigned char bin = (msn << 4) + lsn;
if (length-- <= 0) return -1;
*buff++ = bin;
}
return result;
}
void BinToHex (const unsigned char * buff, int length, char * output, int outLength)
{
char binHex[] = "0123456789ABCDEF";
if (!output || outLength < 4) return;
*output = '\0';
if (!buff || length <= 0 || outLength <= 2 * length)
{
memcpy(output, "ERR", 4);
return;
}
for (; length > 0; --length, outLength -= 2)
{
unsigned char byte = *buff++;
*output++ = binHex[(byte >> 4) & 0x0F];
*output++ = binHex[byte & 0x0F];
}
if (outLength-- <= 0) return;
*output++ = '\0';
}
Using mvp's suggested change, I created this function which includes error checking (invalid characters and uneven length).
This function will convert a hexadecimal string - NOT prepended with "0x" - with an even number of characters to the number of bytes specified. It will return -1 if it encounters an invalid character, or if the hex string has an odd length, and 0 on success.
//convert hexstring to len bytes of data
//returns 0 on success, -1 on error
//data is a buffer of at least len bytes
//hexstring is upper or lower case hexadecimal, NOT prepended with "0x"
int hex2data(unsigned char *data, const unsigned char *hexstring, unsigned int len)
{
unsigned const char *pos = hexstring;
char *endptr;
size_t count = 0;
if ((hexstring[0] == '\0') || (strlen(hexstring) % 2)) {
//hexstring contains no data
//or hexstring has an odd length
return -1;
}
for(count = 0; count < len; count++) {
char buf[5] = {'0', 'x', pos[0], pos[1], 0};
data[count] = strtol(buf, &endptr, 0);
pos += 2 * sizeof(char);
if (endptr[0] != '\0') {
//non-hexadecimal character encountered
return -1;
}
}
return 0;
}