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.
Related
I can use the strtol function for turning a base36 based value (saved as a string) into a long int:
long int val = strtol("ABCZX123", 0, 36);
Is there a standard function that allows the inversion of this? That is, to convert a long int val variable into a base36 string, to obtain "ABCZX123" again?
There's no standard function for this. You'll need to write your own one.
Usage example: https://godbolt.org/z/MhRcNA
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char *reverse(char *str)
{
char *end = str;
char *start = str;
if(!str || !*str) return str;
while(*(end + 1)) end++;
while(end > start)
{
int ch = *end;
*end-- = *start;
*start++ = ch;
}
return str;
}
char *tostring(char *buff, long long num, int base)
{
int sign = num < 0;
char *savedbuff = buff;
if(base < 2 || base >= sizeof(digits)) return NULL;
if(buff)
{
do
{
*buff++ = digits[abs(num % base)];
num /= base;
}while(num);
if(sign)
{
*buff++ = '-';
}
*buff = 0;
reverse(savedbuff);
}
return savedbuff;
}
One of the missing attributes of this "Convert long integer to base 36 string" is string management.
The below suffers from a potential buffer overflow when destination is too small.
char *long_to_string(char *destination, long num, int base);
(Assuming 32-bit long) Consider the overflow of below as the resultant string should be "-10000000000000000000000000000000", which needs 34 bytes to encode the string.
char buffer[33]; // Too small
long_to_string(buffer, LONG_MIN, 2); // Oops!
An alternative would pass in the buffer size and then provide some sort of error signaling when the buffer is too small.
char* longtostr(char *dest, size_t size, long a, int base)
Since C99, code instead could use a compound literal to provide the needed space - without calling code trying to compute the needed size nor explicitly allocate the buffer.
The returned string pointer from TO_BASE(long x, int base) is valid until the end of the block.
#include <assert.h>
#include <limits.h>
#define TO_BASE_N (sizeof(long)*CHAR_BIT + 2)
// v. compound literal .v
#define TO_BASE(x, b) my_to_base((char [TO_BASE_N]){""}, (x), (b))
char *my_to_base(char *buf, long a, int base) {
assert(base >= 2 && base <= 36);
long i = a < 0 ? a : -a; // use the negative side - this handle _MIN, _MAX nicely
char *s = &buf[TO_BASE_N - 1];
*s = '\0';
do {
s--;
*s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(i % base)];
i /= base;
} while (i);
if (a < 0) {
s--;
*s = '-';
}
// Could add memmove here to move the used buffer to the beginning
return s;
}
#include <limits.h>
#include <stdio.h>
int main(void) {
long ip1 = 0x01020304;
long ip2 = 0x05060708;
long ip3 = LONG_MIN;
printf("%s %s\n", TO_BASE(ip1, 16), TO_BASE(ip2, 16), TO_BASE(ip3, 16));
printf("%s %s\n", TO_BASE(ip1, 2), TO_BASE(ip2, 2), TO_BASE(ip3, 2));
puts(TO_BASE(ip1, 8));
puts(TO_BASE(ip1, 36));
puts(TO_BASE(ip3, 10));
}
Here is another option with no need for source array of charaters, but less portable since not all character encodings have contiguous alphabetic characters, for example EBCDIC. Test HERE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
char get_chars(long long value)
{
if (value >= 0 && value <= 9)
return value + '0';
else
return value - 10 + 'A';
}
void reverse_string(char *str)
{
int len = strlen(str);
for (int i = 0; i < len/2; i++)
{
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
}
char* convert_to_base(char *res, int base, long long input)
{
bool flag = 0;
int index = 0;
if(input < 0){
input = llabs(input);
flag = 1;
}
else if(input == 0){
res[index++] = '0';
res[index] = '\0';
return res;
}
while(input > 0)
{
res[index++] = get_chars(input % base);
input /= base;
}
if(flag){
res[index++] = '-';
}
res[index] = '\0';
reverse_string(res);
return res;
}
int main() {
long long input = 0;
printf("** Integer to Base-36 **\n ");
printf("Enter a valid number: ");
scanf("%lld", &input);
if(input >= LLONG_MAX && input <= LLONG_MIN){
printf("Invalid number");
return 0;
}
int base = 36;
char res[100];
printf("%lld -> %s\n", input, convert_to_base(res, base, input));
return 0;
}
I can use the strtol function for turning a base36 based value (saved as a string) into a long int:
long int val = strtol("ABCZX123", 0, 36);
Is there a standard function that allows the inversion of this? That is, to convert a long int val variable into a base36 string, to obtain "ABCZX123" again?
There's no standard function for this. You'll need to write your own one.
Usage example: https://godbolt.org/z/MhRcNA
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char *reverse(char *str)
{
char *end = str;
char *start = str;
if(!str || !*str) return str;
while(*(end + 1)) end++;
while(end > start)
{
int ch = *end;
*end-- = *start;
*start++ = ch;
}
return str;
}
char *tostring(char *buff, long long num, int base)
{
int sign = num < 0;
char *savedbuff = buff;
if(base < 2 || base >= sizeof(digits)) return NULL;
if(buff)
{
do
{
*buff++ = digits[abs(num % base)];
num /= base;
}while(num);
if(sign)
{
*buff++ = '-';
}
*buff = 0;
reverse(savedbuff);
}
return savedbuff;
}
One of the missing attributes of this "Convert long integer to base 36 string" is string management.
The below suffers from a potential buffer overflow when destination is too small.
char *long_to_string(char *destination, long num, int base);
(Assuming 32-bit long) Consider the overflow of below as the resultant string should be "-10000000000000000000000000000000", which needs 34 bytes to encode the string.
char buffer[33]; // Too small
long_to_string(buffer, LONG_MIN, 2); // Oops!
An alternative would pass in the buffer size and then provide some sort of error signaling when the buffer is too small.
char* longtostr(char *dest, size_t size, long a, int base)
Since C99, code instead could use a compound literal to provide the needed space - without calling code trying to compute the needed size nor explicitly allocate the buffer.
The returned string pointer from TO_BASE(long x, int base) is valid until the end of the block.
#include <assert.h>
#include <limits.h>
#define TO_BASE_N (sizeof(long)*CHAR_BIT + 2)
// v. compound literal .v
#define TO_BASE(x, b) my_to_base((char [TO_BASE_N]){""}, (x), (b))
char *my_to_base(char *buf, long a, int base) {
assert(base >= 2 && base <= 36);
long i = a < 0 ? a : -a; // use the negative side - this handle _MIN, _MAX nicely
char *s = &buf[TO_BASE_N - 1];
*s = '\0';
do {
s--;
*s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(i % base)];
i /= base;
} while (i);
if (a < 0) {
s--;
*s = '-';
}
// Could add memmove here to move the used buffer to the beginning
return s;
}
#include <limits.h>
#include <stdio.h>
int main(void) {
long ip1 = 0x01020304;
long ip2 = 0x05060708;
long ip3 = LONG_MIN;
printf("%s %s\n", TO_BASE(ip1, 16), TO_BASE(ip2, 16), TO_BASE(ip3, 16));
printf("%s %s\n", TO_BASE(ip1, 2), TO_BASE(ip2, 2), TO_BASE(ip3, 2));
puts(TO_BASE(ip1, 8));
puts(TO_BASE(ip1, 36));
puts(TO_BASE(ip3, 10));
}
Here is another option with no need for source array of charaters, but less portable since not all character encodings have contiguous alphabetic characters, for example EBCDIC. Test HERE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
char get_chars(long long value)
{
if (value >= 0 && value <= 9)
return value + '0';
else
return value - 10 + 'A';
}
void reverse_string(char *str)
{
int len = strlen(str);
for (int i = 0; i < len/2; i++)
{
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
}
char* convert_to_base(char *res, int base, long long input)
{
bool flag = 0;
int index = 0;
if(input < 0){
input = llabs(input);
flag = 1;
}
else if(input == 0){
res[index++] = '0';
res[index] = '\0';
return res;
}
while(input > 0)
{
res[index++] = get_chars(input % base);
input /= base;
}
if(flag){
res[index++] = '-';
}
res[index] = '\0';
reverse_string(res);
return res;
}
int main() {
long long input = 0;
printf("** Integer to Base-36 **\n ");
printf("Enter a valid number: ");
scanf("%lld", &input);
if(input >= LLONG_MAX && input <= LLONG_MIN){
printf("Invalid number");
return 0;
}
int base = 36;
char res[100];
printf("%lld -> %s\n", input, convert_to_base(res, base, input));
return 0;
}
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);
}
I've been having some trouble storing a binary value into an unsigned int array. I was trying to pass through the binary representation as a char array however it's not working as I had hoped. What I was doing was going through the char array using a while loop and assigning each number to an element to the unsigned int array but that is completely wrong. I just pretty much want to know how to store a binary value into an unsigned int. How do I show zeros in front? I've tried putting in the array just the binary value without 0s at the front but that wasn't working. Could I convert the binary to int value and then convert it back at print time?
Here is the basic code for the function
void setstring(unsigned int array[10], char *bitString) {
len=strlen(bitString);
for (int i=1; i<=10; i++) {
for (int p=1; d%32!=0; d++) {
array[10-i]=bitString[len-];
}
}
}
The printing is just meant to print the bitString or the array but at the moment nothing is printing at all. The print is simply a for loop which iterates through the unsigned int array.
You might be looking for a function to set particular bits of an unsigned char variable.
Try using this to set bits
void setBit(unsigned char *target, int pos)
{
//pos must be < sizeof(unsigned char)
unsigned char mask=1<<pos;
*target = *target | mask;
}
And this to unset bits
void unsetBit(unsigned char *target, int pos)
{
unsigned char mask=~(1<<pos);
*target = *target & mask;
}
Note that pos begins from 0.
You could use these functions for displaying the bits:
int getBit(unsigned char target, int pos)
{
target = target>>pos;
return target & 1;
}
void printBits(unsigned char target)
{
int i;
for(i=sizeof(target)*8-1; i>=0; --i)
{
printf("%d", getBit(target, i));
}
}
In these functions the target variable is passed by reference.
Example:
unsigned char a=0;
setBit(&a, 0);
setBit(&a, 1);
setBit(&a, 6);
printf("\nBit pattern is: ");
printBits(a);
printf(". Value is %d.", a);
would print
Bit pattern is: 01000011. Value is 67.
Further
unsetBit(&a, 1);
printf("\nBit pattern is: ");
printBits(a);
printf(". Value is %d.", a);
would give
Bit pattern is: 01000001. Value is 65.
EDIT: This is a good place to learn bit manipulation.
Here is your (set) of functions :
int binary_string_to_integer(const char *str, unsigned int *vl)
{
unsigned int value = 0;
int result = 0;
if (str == NULL || vl == NULL || !strlen(str)) result = -1;
if (!result)
{
while (!result && *str)
{
if (*str != '1' && *str != '0')
{
result = -1;
}
value <<= 1;
value += (*str++ == '1');
}
}
if (!result) *vl = value;
return result;
}
int binary_string_to_integer_array_of_0_or_1(const char *str, int *vl, int skipzeroes)
{
int result = 0;
if (str == NULL || vl == NULL || !strlen(str)) result = -1;
if (!result)
{
while (*str)
{
if (*str != '1' && *str != '0')
{
result = -1;
break;
}
if (skipzeroes && !result && *str == '0')
{
str++;
continue;
}
*(vl + result++) = (*str++ == '1');
}
}
return result;
}
char *reverse(char *str)
{
char tmp;
size_t len;
if (str != NULL)
{
len = strlen(str);
for (size_t i = 0; i < len / 2; i++)
{
tmp = *(str + i);
*(str + i) = *(str + len - i - 1);
*(str + len - i - 1) = tmp;
}
}
return str;
}
char *uint_to_binary_string(unsigned int vl, char *buff)
{
char *ptr = buff;
if (buff != NULL)
{
while (vl)
{
*ptr++ = '0' + (vl & 1);
vl >>= 1;
}
}
*ptr = 0;
return reverse(buff);
}
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;
}