Drawing Fonts on screen in C - c

I emulated a screen with the SDL library. I want to draw fonts on this screen, simply using a "draw_pixel" function I already made.
I searched a lot on the Internet.
I found this website http://jared.geek.nz/2014/jan/custom-fonts-for-microcontrollers and the code works well. However it does not support variable-width characters
I only want to use source code.
Could you please tell me if there is a source code or a light library to draw fonts from pixels ?
EDIT : Here is my code I changed from M Oehm answer.
int DrawChar(char c, uint8_t x, uint8_t y, int r, int g, int b, SDL_Surface *rectangle, SDL_Surface *ecran, SDL_Rect position)
{
uint8_t i,j;
// Convert the character to an index
c = c & 0x7F;
if (c < ' ') {
c = 0;
} else {
c -= ' ';
}
const uint8_t* chr = font[c];
int w = chr[0];
chr++;
for (j = 0; j < w; j++) {
for (i = 0; i < CHAR_HEIGHT; i++) {
if (chr[j] & (1 << i)) {
draw_pixel(x+j, y+i, r, g, b, rectangle, ecran, position);
}
}
}
return w + CHAR_GAP;
}
void DrawString(const char* str, uint8_t x, uint8_t y, int r, int g, int b, SDL_Surface *rectangle, SDL_Surface *ecran, SDL_Rect position)
{
while (*str) {
x += DrawChar(*str++, x, y, r, g, b, rectangle, ecran, position);
}
}
const unsigned char font[96][6] = {
{3, 0x00, 0x00, 0x00}, //
{3, 0x00, 0x2f, 0x00}, // !
{4, 0x03, 0x00, 0x00, 0x03}, // "
Here is the result : The characters are still at the same size.
http://hpics.li/d54f000
EDIT :
The solution is here http://www.riuson.com/lcd-image-converter
You will have to change a bit the code because they are some mistakes, but it works.

You can easily extend the given code to variable-width characters. Change the definition of the font:
const unsigned char font[96][10] = {
{3, 0x00, 0x00, 0x00}, //
{3, 0x00, 0x2f, 0x00}, // !
{4, 0x03, 0x00, 0x00, 0x03}, // "
...
};
The first entry is the width of the character. The second dimension must be chosen to accomodate the widest character. It can be 9 pixels wide in this example.
Then extend the DrawChar function to use the given width and alo to return the width that the drwing position should advance, which is the width of the character plus a certain gap. (You can make the gap a parameter, so that you can print double-spaced text.)
The DrawString function then makes use of the returned width:
int DrawChar(char c, uint8 x, uint8 y, uint8 brightness)
{
uint8 i, j;
// Convert the character to an index
c = c & 0x7F;
if (c < ' ') {
c = 0;
} else {
c -= ' ';
}
const uint8* chr = font[c];
int w = chr[0];
chr++;
for (j = 0; j < w; j++) {
for (i = 0; i < CHAR_HEIGHT; i++) {
if (chr[j] & (1 << i)) {
DrawPixel(x + j, y + i, brightness);
}
}
}
return w + CHAR_GAP;
}
void DrawString(const char* str, uint8 x, uint8 y, uint8 brightness)
{
while (*str) {
x += DrawChar(*str++, x, y, brightness);
}
}
Edit: Here's a more complete example which defines only some letters:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef unsigned char uint8;
char screen[25][80];
#define CHAR_HEIGHT 8
#define CHAR_GAP 2
const unsigned char font[96][10] = {
[' ' - 32] = {1, 0x00},
['A' - 32] = {5, 0x3e, 0x09, 0x09, 0x09, 0x3e},
['B' - 32] = {5, 0x3f, 0x25, 0x25, 0x25, 0x19},
['D' - 32] = {5, 0x3f, 0x21, 0x21, 0x21, 0x1e},
['E' - 32] = {5, 0x3f, 0x25, 0x25, 0x25, 0x21},
['H' - 32] = {5, 0x3f, 0x04, 0x04, 0x04, 0x3f},
['I' - 32] = {1, 0x3f},
['L' - 32] = {4, 0x3f, 0x20, 0x20, 0x20},
['M' - 32] = {7, 0x3f, 0x02, 0x04, 0x18, 0x04, 0x02, 0x3f},
['O' - 32] = {5, 0x1e, 0x21, 0x21, 0x21, 0x1e},
['P' - 32] = {5, 0x3f, 0x09, 0x09, 0x09, 0x06},
['R' - 32] = {5, 0x3f, 0x09, 0x19, 0x19, 0x26},
['S' - 32] = {5, 0x22, 0x25, 0x25, 0x25, 0x19},
['W' - 32] = {7, 0x07, 0x38, 0x0c, 0x03, 0x0c, 0x38, 0x07},
};
void DrawPixel(int x, int y, uint8 c)
{
screen[y][x] = c;
}
int DrawChar(char c, uint8 x, uint8 y, uint8 brightness)
{
uint8 i, j;
// Convert the character to an index
c = c & 0x7F;
if (c < ' ') {
c = 0;
} else {
c -= ' ';
}
const uint8* chr = font[c];
int w = chr[0];
chr++;
for (j = 0; j < w; j++) {
for (i = 0; i < CHAR_HEIGHT; i++) {
if (chr[j] & (1 << i)) {
DrawPixel(x + j, y + i, brightness);
}
}
}
return w + CHAR_GAP;
}
void DrawString(const char* str, uint8 x, uint8 y, uint8 brightness)
{
while (*str) {
x += DrawChar(*str++, x, y, brightness);
}
}
int main()
{
int i;
memset(screen, '.', sizeof(screen));
DrawString("HELLO WORLD", 2, 2, 'O');
DrawString("MISSISSIPPI", 8, 10, '#');
for (i = 0; i < 25; i++) printf("%.80s\n", screen[i]);
return 0;
}

Related

Convert String to array of char in C [duplicate]

Is there any standard C function that converts from hexadecimal string to byte array?
I do not want to write my own function.
As far as I know, there's no standard function to do so, but it's simple to achieve in the following manner:
#include <stdio.h>
int main(int argc, char **argv) {
const char hexstring[] = "DEadbeef10203040b00b1e50", *pos = hexstring;
unsigned char val[12];
/* WARNING: no sanitization or error-checking whatsoever */
for (size_t count = 0; count < sizeof val/sizeof *val; count++) {
sscanf(pos, "%2hhx", &val[count]);
pos += 2;
}
printf("0x");
for(size_t count = 0; count < sizeof val/sizeof *val; count++)
printf("%02x", val[count]);
printf("\n");
return 0;
}
Edit
As Al pointed out, in case of an odd number of hex digits in the string, you have to make sure you prefix it with a starting 0. For example, the string "f00f5" will be evaluated as {0xf0, 0x0f, 0x05} erroneously by the above example, instead of the proper {0x0f, 0x00, 0xf5}.
Amended the example a little bit to address the comment from #MassimoCallegari
I found this question by Googling for the same thing. I don't like the idea of calling sscanf() or strtol() since it feels like overkill. I wrote a quick function which does not validate that the text is indeed the hexadecimal presentation of a byte stream, but will handle odd number of hex digits:
uint8_t tallymarker_hextobin(const char * str, uint8_t * bytes, size_t blen)
{
uint8_t pos;
uint8_t idx0;
uint8_t idx1;
// mapping of ASCII characters to hex values
const uint8_t hashmap[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // !"#$%&'
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ()*+,-./
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // #ABCDEFG
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // HIJKLMNO
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // PQRSTUVW
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // XYZ[\]^_
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // `abcdefg
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hijklmno
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pqrstuvw
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xyz{|}~.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ........
};
bzero(bytes, blen);
for (pos = 0; ((pos < (blen*2)) && (pos < strlen(str))); pos += 2)
{
idx0 = (uint8_t)str[pos+0];
idx1 = (uint8_t)str[pos+1];
bytes[pos/2] = (uint8_t)(hashmap[idx0] << 4) | hashmap[idx1];
};
return(0);
}
Apart from the excellent answers above I though I would write a C function that does not use any libraries and has some guards against bad strings.
uint8_t* datahex(char* string) {
if(string == NULL)
return NULL;
size_t slength = strlen(string);
if((slength % 2) != 0) // must be even
return NULL;
size_t dlength = slength / 2;
uint8_t* data = malloc(dlength);
memset(data, 0, dlength);
size_t index = 0;
while (index < slength) {
char c = string[index];
int value = 0;
if(c >= '0' && c <= '9')
value = (c - '0');
else if (c >= 'A' && c <= 'F')
value = (10 + (c - 'A'));
else if (c >= 'a' && c <= 'f')
value = (10 + (c - 'a'));
else {
free(data);
return NULL;
}
data[(index/2)] += value << (((index + 1) % 2) * 4);
index++;
}
return data;
}
Explanation:
a. index / 2 | Division between integers will round down the value, so 0/2 = 0, 1/2 = 0, 2/2 = 1, 3/2 = 1, 4/2 = 2, 5/2 = 2, etc. So, for every 2 string characters we add the value to 1 data byte.
b. (index + 1) % 2 | We want odd numbers to result to 1 and even to 0 since the first digit of a hex string is the most significant and needs to be multiplied by 16. so for index 0 => 0 + 1 % 2 = 1, index 1 => 1 + 1 % 2 = 0 etc.
c. << 4 | Shift by 4 is multiplying by 16. example: b00000001 << 4 = b00010000
For short strings, strtol, strtoll, and strtoimax will work just fine (note that the third argument is the base to use in processing the string...set it to 16). If your input is longer than number-of-bits-in-the-longest-integer-type/4 then you'll need one of the more flexible methods suggested by other answers.
By some modification form user411313's code, following works for me:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main ()
{
char *hexstring = "deadbeef10203040b00b1e50";
int i;
unsigned int bytearray[12];
uint8_t str_len = strlen(hexstring);
for (i = 0; i < (str_len / 2); i++) {
sscanf(hexstring + 2*i, "%02x", &bytearray[i]);
printf("bytearray %d: %02x\n", i, bytearray[i]);
}
return 0;
}
A fleshed out version of Michael Foukarakis post (since I don't have the "reputation" to add a comment to that post yet):
#include <stdio.h>
#include <string.h>
void print(unsigned char *byte_array, int byte_array_size)
{
int i = 0;
printf("0x");
for(; i < byte_array_size; i++)
{
printf("%02x", byte_array[i]);
}
printf("\n");
}
int convert(const char *hex_str, unsigned char *byte_array, int byte_array_max)
{
int hex_str_len = strlen(hex_str);
int i = 0, j = 0;
// The output array size is half the hex_str length (rounded up)
int byte_array_size = (hex_str_len+1)/2;
if (byte_array_size > byte_array_max)
{
// Too big for the output array
return -1;
}
if (hex_str_len % 2 == 1)
{
// hex_str is an odd length, so assume an implicit "0" prefix
if (sscanf(&(hex_str[0]), "%1hhx", &(byte_array[0])) != 1)
{
return -1;
}
i = j = 1;
}
for (; i < hex_str_len; i+=2, j++)
{
if (sscanf(&(hex_str[i]), "%2hhx", &(byte_array[j])) != 1)
{
return -1;
}
}
return byte_array_size;
}
void main()
{
char *examples[] = { "", "5", "D", "5D", "5Df", "deadbeef10203040b00b1e50", "02invalid55" };
unsigned char byte_array[128];
int i = 0;
for (; i < sizeof(examples)/sizeof(char *); i++)
{
int size = convert(examples[i], byte_array, 128);
if (size < 0)
{
printf("Failed to convert '%s'\n", examples[i]);
}
else if (size == 0)
{
printf("Nothing to convert for '%s'\n", examples[i]);
}
else
{
print(byte_array, size);
}
}
}
Here is HexToBin and BinToHex relatively clean and readable.
(Note originally there were returned enum error codes through an error logging system not a simple -1 or -2.)
typedef unsigned char ByteData;
ByteData HexChar (char c)
{
if ('0' <= c && c <= '9') return (ByteData)(c - '0');
if ('A' <= c && c <= 'F') return (ByteData)(c - 'A' + 10);
if ('a' <= c && c <= 'f') return (ByteData)(c - 'a' + 10);
return (ByteData)(-1);
}
ssize_t HexToBin (const char* s, ByteData * buff, ssize_t length)
{
ssize_t result = 0;
if (!s || !buff || length <= 0) return -2;
while (*s)
{
ByteData nib1 = HexChar(*s++);
if ((signed)nib1 < 0) return -3;
ByteData nib2 = HexChar(*s++);
if ((signed)nib2 < 0) return -4;
ByteData bin = (nib1 << 4) + nib2;
if (length-- <= 0) return -5;
*buff++ = bin;
++result;
}
return result;
}
void BinToHex (const ByteData * buff, ssize_t length, char * output, ssize_t outLength)
{
char binHex[] = "0123456789ABCDEF";
if (!output || outLength < 4) return (void)(-6);
*output = '\0';
if (!buff || length <= 0 || outLength <= 2 * length)
{
memcpy(output, "ERR", 4);
return (void)(-7);
}
for (; length > 0; --length, outLength -= 2)
{
ByteData byte = *buff++;
*output++ = binHex[(byte >> 4) & 0x0F];
*output++ = binHex[byte & 0x0F];
}
if (outLength-- <= 0) return (void)(-8);
*output++ = '\0';
}
Following is the solution I wrote up for performance reasons:
void hex2bin(const char* in, size_t len, unsigned char* out) {
static const unsigned char TBL[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 58, 59, 60, 61,
62, 63, 64, 10, 11, 12, 13, 14, 15, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
90, 91, 92, 93, 94, 95, 96, 10, 11, 12, 13, 14, 15
};
static const unsigned char *LOOKUP = TBL - 48;
const char* end = in + len;
while(in < end) *(out++) = LOOKUP[*(in++)] << 4 | LOOKUP[*(in++)];
}
Example:
unsigned char seckey[32];
hex2bin("351aaaec0070d13d350afae2bc43b68c7e590268889869dde489f2f7988f3fee", 64, seckey);
/*
seckey = {
53, 26, 170, 236, 0, 112, 209, 61, 53, 10, 250, 226, 188, 67, 182, 140,
126, 89, 2, 104, 136, 152, 105, 221, 228, 137, 242, 247, 152, 143, 63, 238
};
*/
If you don't need to support lowercase:
static const unsigned char TBL[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 58, 59,
60, 61, 62, 63, 64, 10, 11, 12, 13, 14, 15
};
you can use this function which
written with performance in mind (for embedded processors), no scanf, strtol or dynamic memory allocation
has guard against output buffer overflow and odd input str len
/// in: valid chars are 0-9 + A-F + a-f
/// out_len_max==0: convert until the end of input string, out_len_max>0 only convert this many numbers
/// returns actual out size
int hexStr2Arr(unsigned char* out, const char* in, size_t out_len_max = 0)
{
if (!out_len_max)
out_len_max = 2147483647; // INT_MAX
const int in_len = strnlen(in, out_len_max * 2);
if (in_len % 2 != 0)
return -1; // error, in str len should be even
// calc actual out len
const int out_len = out_len_max < (in_len / 2) ? out_len_max : (in_len / 2);
for (int i = 0; i < out_len; i++) {
char ch0 = in[2 * i];
char ch1 = in[2 * i + 1];
uint8_t nib0 = (ch0 & 0xF) + (ch0 >> 6) | ((ch0 >> 3) & 0x8);
uint8_t nib1 = (ch1 & 0xF) + (ch1 >> 6) | ((ch1 >> 3) & 0x8);
out[i] = (nib0 << 4) | nib1;
}
return out_len;
}
usage:
unsigned char result[128];
memset(result, 0, 128); // optional
printf("result len=%d\n", hexStr2Arr(result, "0a0B10")); // result = [0A 0B 10 00 00 ...]
memset(result, 0, 128); // optional
// only convert single number
printf("result len=%d\n", hexStr2Arr(result, "0a0B10", 1)); // result = [0A 00 00 00 00 ...]
hextools.h
#ifndef HEX_TOOLS_H
#define HEX_TOOLS_H
char *bin2hex(unsigned char*, int);
unsigned char *hex2bin(const char*);
#endif // HEX_TOOLS_H
hextools.c
#include <stdlib.h>
char *bin2hex(unsigned char *p, int len)
{
char *hex = malloc(((2*len) + 1));
char *r = hex;
while(len && p)
{
(*r) = ((*p) & 0xF0) >> 4;
(*r) = ((*r) <= 9 ? '0' + (*r) : 'A' - 10 + (*r));
r++;
(*r) = ((*p) & 0x0F);
(*r) = ((*r) <= 9 ? '0' + (*r) : 'A' - 10 + (*r));
r++;
p++;
len--;
}
*r = '\0';
return hex;
}
unsigned char *hex2bin(const char *str)
{
int len, h;
unsigned char *result, *err, *p, c;
err = malloc(1);
*err = 0;
if (!str)
return err;
if (!*str)
return err;
len = 0;
p = (unsigned char*) str;
while (*p++)
len++;
result = malloc((len/2)+1);
h = !(len%2) * 4;
p = result;
*p = 0;
c = *str;
while(c)
{
if(('0' <= c) && (c <= '9'))
*p += (c - '0') << h;
else if(('A' <= c) && (c <= 'F'))
*p += (c - 'A' + 10) << h;
else if(('a' <= c) && (c <= 'f'))
*p += (c - 'a' + 10) << h;
else
return err;
str++;
c = *str;
if (h)
h = 0;
else
{
h = 4;
p++;
*p = 0;
}
}
return result;
}
main.c
#include <stdio.h>
#include "hextools.h"
int main(void)
{
unsigned char s[] = { 0xa0, 0xf9, 0xc3, 0xde, 0x44 };
char *hex = bin2hex(s, sizeof s);
puts(hex);
unsigned char *bin;
bin = hex2bin(hex);
puts(bin2hex(bin, 5));
size_t k;
for(k=0; k<5; k++)
printf("%02X", bin[k]);
putchar('\n');
return 0;
}
char *hexstring = "deadbeef10203040b00b1e50", *pos = hexstring;
unsigned char val[12];
while( *pos )
{
if( !((pos-hexstring)&1) )
sscanf(pos,"%02x",&val[(pos-hexstring)>>1]);
++pos;
}
sizeof(val)/sizeof(val[0]) is redundant!
In main()
{
printf("enter string :\n");
fgets(buf, 200, stdin);
unsigned char str_len = strlen(buf);
k=0;
unsigned char bytearray[100];
for(j=0;j<str_len-1;j=j+2)
{ bytearray[k++]=converttohex(&buffer[j]);
printf(" %02X",bytearray[k-1]);
}
}
Use this
int converttohex(char * val)
{
unsigned char temp = toupper(*val);
unsigned char fin=0;
if(temp>64)
temp=10+(temp-65);
else
temp=temp-48;
fin=(temp<<4)&0xf0;
temp = toupper(*(val+1));
if(temp>64)
temp=10+(temp-65);
else
temp=temp-48;
fin=fin|(temp & 0x0f);
return fin;
}
This is a modified function from a similar question, modified as per the suggestion of https://stackoverflow.com/a/18267932/700597.
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;
}
Two short routines to parse a byte or a word, using strchr().
// HexConverter.h
#ifndef HEXCONVERTER_H
#define HEXCONVERTER_H
unsigned int hexToByte (const char *hexString);
unsigned int hexToWord (const char *hexString);
#endif
// HexConverter.c
#include <string.h> // for strchr()
#include <ctype.h> // for toupper()
unsigned int hexToByte (const char *hexString)
{
unsigned int value;
const char *hexDigits = "0123456789ABCDEF";
value = 0;
if (hexString != NULL)
{
char *ptr;
ptr = strchr (hexDigits, toupper(hexString[0]));
if (ptr != NULL)
{
value = (ptr - hexDigits) << 4;
ptr = strchr (hexDigits, toupper(hexString[1]));
if (ptr != NULL)
{
value = value | (ptr - hexDigits);
}
}
}
return value;
}
unsigned int hexToWord (const char *hexString)
{
unsigned int value;
value = 0;
if (hexString != NULL)
{
value = (hexToByte (&hexString[0]) << 8) |
(hexToByte (&hexString[2]));
}
return value;
}
// HexConverterTest.c
#include <stdio.h>
#include "HexConverter.h"
int main (int argc, char **argv)
{
(void)argc; // not used
(void)argv; // not used
unsigned int value;
char *hexString;
hexString = "2a";
value = hexToByte (hexString);
printf ("%s == %x (%u)\n", hexString, value, value);
hexString = "1234";
value = hexToWord (hexString);
printf ("%s == %x (%u)\n", hexString, value, value);
hexString = "0102030405060708090a10ff";
printf ("Hex String: %s\n", hexString);
for (unsigned int idx = 0; idx < strlen(hexString); idx += 2)
{
value = hexToByte (&hexString[idx]);
printf ("%c%c == %x (%u)\n", hexString[idx], hexString[idx+1],
value, value);
}
return EXIT_SUCCESS;
}
Try the following code:
static unsigned char ascii2byte(char *val)
{
unsigned char temp = *val;
if(temp > 0x60) temp -= 39; // convert chars a-f
temp -= 48; // convert chars 0-9
temp *= 16;
temp += *(val+1);
if(*(val+1) > 0x60) temp -= 39; // convert chars a-f
temp -= 48; // convert chars 0-9
return temp;
}
Here's my version:
/* Convert a hex char digit to its integer value. */
int hexDigitToInt(char digit) {
digit = tolower(digit);
if ('0' <= digit && digit <= '9') //if it's decimal
return (int)(digit - '0');
else if ('a' <= digit && digit <= 'f') //if it's abcdef
return (int)(digit - ('a' - 10));
else
return -1; //value not in [0-9][a-f] range
}
/* Decode a hex string. */
char *decodeHexString(const char *hexStr) {
char* decoded = malloc(strlen(hexStr)/2+1);
char* hexStrPtr = (char *)hexStr;
char* decodedPtr = decoded;
while (*hexStrPtr != '\0') { /* Step through hexStr, two chars at a time. */
*decodedPtr = 16 * hexDigitToInt(*hexStrPtr) + hexDigitToInt(*(hexStrPtr+1));
hexStrPtr += 2;
decodedPtr++;
}
*decodedPtr = '\0'; /* final null char */
return decoded;
}
Could it be simpler?!
uint8_t hex(char ch) {
uint8_t r = (ch > 57) ? (ch - 55) : (ch - 48);
return r & 0x0F;
}
int to_byte_array(const char *in, size_t in_size, uint8_t *out) {
int count = 0;
if (in_size % 2) {
while (*in && out) {
*out = hex(*in++);
if (!*in)
return count;
*out = (*out << 4) | hex(*in++);
*out++;
count++;
}
return count;
} else {
while (*in && out) {
*out++ = (hex(*in++) << 4) | hex(*in++);
count++;
}
return count;
}
}
int main() {
char hex_in[] = "deadbeef10203040b00b1e50";
uint8_t out[32];
int res = to_byte_array(hex_in, sizeof(hex_in) - 1, out);
for (size_t i = 0; i < res; i++)
printf("%02x ", out[i]);
printf("\n");
system("pause");
return 0;
}
For newbies and to improve #Michael's answer here's a full version:
// out needs to be at least len/2+1 bytes long
// length will be returned
int hexStrToBin(char* out, const char *str)
{
int i, len = strlen(str);
for (i = 0; i < len; i++)
{
// Reads str & stores in op
sscanf(str, "%2hhx", &op[i]);
str += 2;
}
return len/2;
}
No. But it's relatively trivial to achieve using sscanf in a loop.
The best way I know:
int hex2bin_by_zibri(char *source_str, char *dest_buffer)
{
char *line = source_str;
char *data = line;
int offset;
int read_byte;
int data_len = 0;
while (sscanf(data, " %02x%n", &read_byte, &offset) == 1) {
dest_buffer[data_len++] = read_byte;
data += offset;
}
return data_len;
}
The function returns the number of converted bytes saved in dest_buffer.
The input string can contain spaces and mixed case letters.
"01 02 03 04 ab Cd eF garbage AB"
translates to dest_buffer containing
01 02 03 04 ab cd ef
and also
"01020304abCdeFgarbageAB"
translates as before.
Parsing stops at the first "error".
Here is a solution to deal with files, which may be used more frequently...
int convert(char *infile, char *outfile) {
char *source = NULL;
FILE *fp = fopen(infile, "r");
long bufsize;
if (fp != NULL) {
/* Go to the end of the file. */
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
bufsize = ftell(fp);
if (bufsize == -1) { /* Error */ }
/* Allocate our buffer to that size. */
source = malloc(sizeof(char) * (bufsize + 1));
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }
/* Read the entire file into memory. */
size_t newLen = fread(source, sizeof(char), bufsize, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
} else {
source[newLen++] = '\0'; /* Just to be safe. */
}
}
fclose(fp);
}
int sourceLen = bufsize - 1;
int destLen = sourceLen/2;
unsigned char* dest = malloc(destLen);
short i;
unsigned char highByte, lowByte;
for (i = 0; i < sourceLen; i += 2)
{
highByte = toupper(source[i]);
lowByte = toupper(source[i + 1]);
if (highByte > 0x39)
highByte -= 0x37;
else
highByte -= 0x30;
if (lowByte > 0x39)
lowByte -= 0x37;
else
lowByte -= 0x30;
dest[i / 2] = (highByte << 4) | lowByte;
}
FILE *fop = fopen(outfile, "w");
if (fop == NULL) return 1;
fwrite(dest, 1, destLen, fop);
fclose(fop);
free(source);
free(dest);
return 0;
}

Running code multiple times in a row has different results even with same input data

I need to convert a byte array to base58. I found the following function that is faster than using Bignums:
void EncodeAdrBase58(const uint8_t *bytes, unsigned char* result) //only accepts 25-byte arrays (1 byte for addressbyte, 20 for hash160, and 4 for checksum)
{
unsigned char digits[25 * 137 / 100];
int digitslen = 1;
for (int i = 0; i < 25; i++)
{
unsigned int carry = (unsigned int)bytes[i];
for (int j = 0; j < digitslen; j++)
{
carry += (unsigned int)(digits[j]) << 8;
digits[j] = (unsigned char)(carry % 58);
carry /= 58;
}
while (carry > 0)
{
digits[digitslen++] = (unsigned char)(carry % 58);
carry /= 58;
}
}
int resultlen = 0;
// leading zero bytes
for (; resultlen < 25 && bytes[resultlen] == 0;)
result[resultlen++] = '1';
// reverse
for (int i = 0; i < digitslen; i++)
result[resultlen + i] = ALPHABET[digits[digitslen - 1 - i]];
result[digitslen + resultlen] = 0;
}
When trying to test its speed I found that it gives the right answer- the first time. Then when running multiple times in a row with the same input data, it gives different answers. Oddly enough, those different answers are the same every time it's run. My testing method:
void encB58()
{
uint8_t data[] = { 0x00, 0x01, 0x09, 0x66, 0x77, 0x60, 0x06, 0x95, 0x3D, 0x55, 0x67, 0x43, 0x9E, 0x5E, 0x39, 0xF8, 0x6A, 0x0D, 0x27, 0x3B, 0xEE, 0xD6, 0x19, 0x67, 0xF6 };
unsigned char result[25 * 137 / 100];
for (int i = 0; i < 2; i++)
{
EncodeAdrBase58(&data, &result);
printf("%s\n", result);
}
}
If I run encB58(), I get
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
1cXBanFJTEfPPbGcWw9Crh7mFGDvXmvSXuKs
The first one is correct. If I change the loop in encB58() to 4 times, I get
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
1cXBanFJTEfPPbGcWw9Crh7mFGDvXmvSXuKs
12XoTKEDFdsWtAa7RJF7EvMJhdDv3EFu4VeS9
1FD5HoTinBXBszw6CoxPddSb6UkH3yvzYogZ
Also, if I change encB58() to use two different inputs and output to two different char arrays
void encB58()
{
uint8_t data[] = { 0x00, 0x01, 0x09, 0x66, 0x77, 0x60, 0x06, 0x95, 0x3D, 0x55, 0x67, 0x43, 0x9E, 0x5E, 0x39, 0xF8, 0x6A, 0x0D, 0x27, 0x3B, 0xEE, 0xD6, 0x19, 0x67, 0xF6 };
uint8_t data2[] = { 0x00, 0xED, 0xA9, 0x96, 0xA7, 0x21, 0x2D, 0x7D, 0xBB, 0x38, 0x22, 0xE8, 0x53, 0x20, 0x68, 0x91, 0x49, 0x95, 0x00, 0xDE, 0x4C, 0xD6, 0xB3, 0x5E, 0x9C };
unsigned char result[25 * 137 / 100];
unsigned char result2[25 * 137 / 100];
for (int i = 0; i < 2; i++)
{
EncodeAdrBase58(&data, &result);
EncodeAdrBase58(&data2, &result2);
printf("%s\n", result);
printf("%s\n", result2);
}
}
I get the following:
15uASzsR5JsK31Vs3ViKNV6fUM5T8TMp123AV
1rjdMG92vdQwp1bBmt3LpCnRyWaL9TzQ6Jbm
14g862Go94gqhyXQdndhKjZ5ZB8XeC3qqjiMT
1oBcJS1SK7taZQsGPXWYH2WEciL4EVzVRnfD
NONE of those are correct. What is happening here?

How to calculate modular multplication of array elements to integers in c?

Consider the following:
uint8_t message[15] = {
0x32, 0xdc, 0x21, 0x55, 0x3f, 0x87, 0xc8, 0x1e,
0x85, 0x10, 0x43, 0xf9, 0x93, 0x34, 0x1a
};
uint64_t num = 0xa1b2c33412;
I want to multiply the above variable num to the array message[]. The pseudo-code for what I have need, is following:
uint8_t message[15] = {
0x32, 0xdc, 0x21, 0x55, 0x3f, 0x87, 0xc8, 0x1e,
0x85, 0x10, 0x43, 0xf9, 0x93, 0x34, 0x1a
};
uint64_t num = 0xa1b2c33412;
uint64_t p = 0x31ba62ca3037;
uint64_t result = 0x00;
result = moduloMultiplication(message, num, p); // (message * num) (mod p)
I am expecting the following results:
num * msg = num*msg mod p
num * msg = 0x2bf2d18cdf92 (Final result)
Is there any way to multiply the array with value of typeuint64_t?
Any help regarding this will be appreciated...
Assuming the number stored in the 15-byte array is in big-endian order, here is a simple solution:
#include <stdio.h>
#include <stdint.h>
uint64_t moduloMultiplication(const uint8_t message[15], size_t n,
uint64_t num, uint64_t p)
{
uint64_t res = 0;
for (size_t i = 0; i < n; i++) {
// assuming `p < 1ULL << 56`
res = (res * 256 + message[i] * num) % p;
}
return res;
}
int main() {
uint8_t message[15] = {
0x32, 0xdc, 0x21, 0x55, 0x3f, 0x87, 0xc8, 0x1e,
0x85, 0x10, 0x43, 0xf9, 0x93, 0x34, 0x1a
};
uint64_t num = 0xa1b2c33412;
uint64_t p = 0x31ba62ca3037;
// result = (message * num) (mod p)
uint64_t result = moduloMultiplication(message, sizeof message, num, p);
printf("%#"PRIx64"\n", result);
return 0;
}
Output: 0x2bf2d18cdf92
The result differs from that in the question because either the message is incorrect, or your intermediary result is approximate: 201FF4CDCFE8C0000000000000000000000000000 seems incorrect.

char array not displaying when passed to a function

Why is the passing of char array not showing?
The location of the pointer is passed to a function.
char plaintext[] = {
0xCD, 0x76, 0x43, 0xF0,
0x72, 0xA4, 0xA0, 0x82,
}
Given
void displayArray(char** plaintext, int size) {
// int newSize = sizeof(**plaintext);
int i;
for(i=0; i < size; ++i) {
printf("%02X ", (0xff & *plaintext[i]));
if (((i+1)% 8) == 0) // as index starts from 0, (i+1)
printf("\n");
}
}
in main()
char* plaintextCopy;
plaintextCopy = (char*) malloc(numberOfItems*sizeof(char));
memcpy(plaintextCopy, plaintext, numberOfItems);
displayArray(&plaintextCopy, numberOfItems);
Based on your code :
void displayArray(char** plaintext, int size)
{
int i;
for(i=0; i < size; i++)
{
printf("%02X ", (0xff & (*plaintext)[i]));
if(((i+1)% 8) == 0) // as index starts from 0, (i+1)
printf("\n");
}
}
int main(void)
{
char plaintext[] = {
0xCD, 0x76, 0x43, 0xF0,
0x72, 0xA4, 0xA0, 0x82,
};
int numberOfItems = sizeof(plaintext);
char* plaintextCopy;
plaintextCopy = (char*) malloc(numberOfItems*sizeof(char));
memcpy(plaintextCopy, plaintext, numberOfItems);
displayArray(&plaintextCopy, numberOfItems);
return 0;
}
It outputs :
CD 76 43 F0 72 A4 A0 82
Also, if you're sending an array that you want to display or change the values of, you don't need to send a double pointer to a function. A regular pointer would do. You should only use double pointers if the original array changes it's location in memory, that is, it's getting a new pointer after the function returns.

Hexadecimal string to byte array in C

Is there any standard C function that converts from hexadecimal string to byte array?
I do not want to write my own function.
As far as I know, there's no standard function to do so, but it's simple to achieve in the following manner:
#include <stdio.h>
int main(int argc, char **argv) {
const char hexstring[] = "DEadbeef10203040b00b1e50", *pos = hexstring;
unsigned char val[12];
/* WARNING: no sanitization or error-checking whatsoever */
for (size_t count = 0; count < sizeof val/sizeof *val; count++) {
sscanf(pos, "%2hhx", &val[count]);
pos += 2;
}
printf("0x");
for(size_t count = 0; count < sizeof val/sizeof *val; count++)
printf("%02x", val[count]);
printf("\n");
return 0;
}
Edit
As Al pointed out, in case of an odd number of hex digits in the string, you have to make sure you prefix it with a starting 0. For example, the string "f00f5" will be evaluated as {0xf0, 0x0f, 0x05} erroneously by the above example, instead of the proper {0x0f, 0x00, 0xf5}.
Amended the example a little bit to address the comment from #MassimoCallegari
I found this question by Googling for the same thing. I don't like the idea of calling sscanf() or strtol() since it feels like overkill. I wrote a quick function which does not validate that the text is indeed the hexadecimal presentation of a byte stream, but will handle odd number of hex digits:
uint8_t tallymarker_hextobin(const char * str, uint8_t * bytes, size_t blen)
{
uint8_t pos;
uint8_t idx0;
uint8_t idx1;
// mapping of ASCII characters to hex values
const uint8_t hashmap[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // !"#$%&'
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ()*+,-./
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // #ABCDEFG
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // HIJKLMNO
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // PQRSTUVW
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // XYZ[\]^_
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // `abcdefg
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hijklmno
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pqrstuvw
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xyz{|}~.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ........
};
bzero(bytes, blen);
for (pos = 0; ((pos < (blen*2)) && (pos < strlen(str))); pos += 2)
{
idx0 = (uint8_t)str[pos+0];
idx1 = (uint8_t)str[pos+1];
bytes[pos/2] = (uint8_t)(hashmap[idx0] << 4) | hashmap[idx1];
};
return(0);
}
Apart from the excellent answers above I though I would write a C function that does not use any libraries and has some guards against bad strings.
uint8_t* datahex(char* string) {
if(string == NULL)
return NULL;
size_t slength = strlen(string);
if((slength % 2) != 0) // must be even
return NULL;
size_t dlength = slength / 2;
uint8_t* data = malloc(dlength);
memset(data, 0, dlength);
size_t index = 0;
while (index < slength) {
char c = string[index];
int value = 0;
if(c >= '0' && c <= '9')
value = (c - '0');
else if (c >= 'A' && c <= 'F')
value = (10 + (c - 'A'));
else if (c >= 'a' && c <= 'f')
value = (10 + (c - 'a'));
else {
free(data);
return NULL;
}
data[(index/2)] += value << (((index + 1) % 2) * 4);
index++;
}
return data;
}
Explanation:
a. index / 2 | Division between integers will round down the value, so 0/2 = 0, 1/2 = 0, 2/2 = 1, 3/2 = 1, 4/2 = 2, 5/2 = 2, etc. So, for every 2 string characters we add the value to 1 data byte.
b. (index + 1) % 2 | We want odd numbers to result to 1 and even to 0 since the first digit of a hex string is the most significant and needs to be multiplied by 16. so for index 0 => 0 + 1 % 2 = 1, index 1 => 1 + 1 % 2 = 0 etc.
c. << 4 | Shift by 4 is multiplying by 16. example: b00000001 << 4 = b00010000
For short strings, strtol, strtoll, and strtoimax will work just fine (note that the third argument is the base to use in processing the string...set it to 16). If your input is longer than number-of-bits-in-the-longest-integer-type/4 then you'll need one of the more flexible methods suggested by other answers.
By some modification form user411313's code, following works for me:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main ()
{
char *hexstring = "deadbeef10203040b00b1e50";
int i;
unsigned int bytearray[12];
uint8_t str_len = strlen(hexstring);
for (i = 0; i < (str_len / 2); i++) {
sscanf(hexstring + 2*i, "%02x", &bytearray[i]);
printf("bytearray %d: %02x\n", i, bytearray[i]);
}
return 0;
}
A fleshed out version of Michael Foukarakis post (since I don't have the "reputation" to add a comment to that post yet):
#include <stdio.h>
#include <string.h>
void print(unsigned char *byte_array, int byte_array_size)
{
int i = 0;
printf("0x");
for(; i < byte_array_size; i++)
{
printf("%02x", byte_array[i]);
}
printf("\n");
}
int convert(const char *hex_str, unsigned char *byte_array, int byte_array_max)
{
int hex_str_len = strlen(hex_str);
int i = 0, j = 0;
// The output array size is half the hex_str length (rounded up)
int byte_array_size = (hex_str_len+1)/2;
if (byte_array_size > byte_array_max)
{
// Too big for the output array
return -1;
}
if (hex_str_len % 2 == 1)
{
// hex_str is an odd length, so assume an implicit "0" prefix
if (sscanf(&(hex_str[0]), "%1hhx", &(byte_array[0])) != 1)
{
return -1;
}
i = j = 1;
}
for (; i < hex_str_len; i+=2, j++)
{
if (sscanf(&(hex_str[i]), "%2hhx", &(byte_array[j])) != 1)
{
return -1;
}
}
return byte_array_size;
}
void main()
{
char *examples[] = { "", "5", "D", "5D", "5Df", "deadbeef10203040b00b1e50", "02invalid55" };
unsigned char byte_array[128];
int i = 0;
for (; i < sizeof(examples)/sizeof(char *); i++)
{
int size = convert(examples[i], byte_array, 128);
if (size < 0)
{
printf("Failed to convert '%s'\n", examples[i]);
}
else if (size == 0)
{
printf("Nothing to convert for '%s'\n", examples[i]);
}
else
{
print(byte_array, size);
}
}
}
Here is HexToBin and BinToHex relatively clean and readable.
(Note originally there were returned enum error codes through an error logging system not a simple -1 or -2.)
typedef unsigned char ByteData;
ByteData HexChar (char c)
{
if ('0' <= c && c <= '9') return (ByteData)(c - '0');
if ('A' <= c && c <= 'F') return (ByteData)(c - 'A' + 10);
if ('a' <= c && c <= 'f') return (ByteData)(c - 'a' + 10);
return (ByteData)(-1);
}
ssize_t HexToBin (const char* s, ByteData * buff, ssize_t length)
{
ssize_t result = 0;
if (!s || !buff || length <= 0) return -2;
while (*s)
{
ByteData nib1 = HexChar(*s++);
if ((signed)nib1 < 0) return -3;
ByteData nib2 = HexChar(*s++);
if ((signed)nib2 < 0) return -4;
ByteData bin = (nib1 << 4) + nib2;
if (length-- <= 0) return -5;
*buff++ = bin;
++result;
}
return result;
}
void BinToHex (const ByteData * buff, ssize_t length, char * output, ssize_t outLength)
{
char binHex[] = "0123456789ABCDEF";
if (!output || outLength < 4) return (void)(-6);
*output = '\0';
if (!buff || length <= 0 || outLength <= 2 * length)
{
memcpy(output, "ERR", 4);
return (void)(-7);
}
for (; length > 0; --length, outLength -= 2)
{
ByteData byte = *buff++;
*output++ = binHex[(byte >> 4) & 0x0F];
*output++ = binHex[byte & 0x0F];
}
if (outLength-- <= 0) return (void)(-8);
*output++ = '\0';
}
Following is the solution I wrote up for performance reasons:
void hex2bin(const char* in, size_t len, unsigned char* out) {
static const unsigned char TBL[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 58, 59, 60, 61,
62, 63, 64, 10, 11, 12, 13, 14, 15, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
90, 91, 92, 93, 94, 95, 96, 10, 11, 12, 13, 14, 15
};
static const unsigned char *LOOKUP = TBL - 48;
const char* end = in + len;
while(in < end) *(out++) = LOOKUP[*(in++)] << 4 | LOOKUP[*(in++)];
}
Example:
unsigned char seckey[32];
hex2bin("351aaaec0070d13d350afae2bc43b68c7e590268889869dde489f2f7988f3fee", 64, seckey);
/*
seckey = {
53, 26, 170, 236, 0, 112, 209, 61, 53, 10, 250, 226, 188, 67, 182, 140,
126, 89, 2, 104, 136, 152, 105, 221, 228, 137, 242, 247, 152, 143, 63, 238
};
*/
If you don't need to support lowercase:
static const unsigned char TBL[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 58, 59,
60, 61, 62, 63, 64, 10, 11, 12, 13, 14, 15
};
you can use this function which
written with performance in mind (for embedded processors), no scanf, strtol or dynamic memory allocation
has guard against output buffer overflow and odd input str len
/// in: valid chars are 0-9 + A-F + a-f
/// out_len_max==0: convert until the end of input string, out_len_max>0 only convert this many numbers
/// returns actual out size
int hexStr2Arr(unsigned char* out, const char* in, size_t out_len_max = 0)
{
if (!out_len_max)
out_len_max = 2147483647; // INT_MAX
const int in_len = strnlen(in, out_len_max * 2);
if (in_len % 2 != 0)
return -1; // error, in str len should be even
// calc actual out len
const int out_len = out_len_max < (in_len / 2) ? out_len_max : (in_len / 2);
for (int i = 0; i < out_len; i++) {
char ch0 = in[2 * i];
char ch1 = in[2 * i + 1];
uint8_t nib0 = (ch0 & 0xF) + (ch0 >> 6) | ((ch0 >> 3) & 0x8);
uint8_t nib1 = (ch1 & 0xF) + (ch1 >> 6) | ((ch1 >> 3) & 0x8);
out[i] = (nib0 << 4) | nib1;
}
return out_len;
}
usage:
unsigned char result[128];
memset(result, 0, 128); // optional
printf("result len=%d\n", hexStr2Arr(result, "0a0B10")); // result = [0A 0B 10 00 00 ...]
memset(result, 0, 128); // optional
// only convert single number
printf("result len=%d\n", hexStr2Arr(result, "0a0B10", 1)); // result = [0A 00 00 00 00 ...]
hextools.h
#ifndef HEX_TOOLS_H
#define HEX_TOOLS_H
char *bin2hex(unsigned char*, int);
unsigned char *hex2bin(const char*);
#endif // HEX_TOOLS_H
hextools.c
#include <stdlib.h>
char *bin2hex(unsigned char *p, int len)
{
char *hex = malloc(((2*len) + 1));
char *r = hex;
while(len && p)
{
(*r) = ((*p) & 0xF0) >> 4;
(*r) = ((*r) <= 9 ? '0' + (*r) : 'A' - 10 + (*r));
r++;
(*r) = ((*p) & 0x0F);
(*r) = ((*r) <= 9 ? '0' + (*r) : 'A' - 10 + (*r));
r++;
p++;
len--;
}
*r = '\0';
return hex;
}
unsigned char *hex2bin(const char *str)
{
int len, h;
unsigned char *result, *err, *p, c;
err = malloc(1);
*err = 0;
if (!str)
return err;
if (!*str)
return err;
len = 0;
p = (unsigned char*) str;
while (*p++)
len++;
result = malloc((len/2)+1);
h = !(len%2) * 4;
p = result;
*p = 0;
c = *str;
while(c)
{
if(('0' <= c) && (c <= '9'))
*p += (c - '0') << h;
else if(('A' <= c) && (c <= 'F'))
*p += (c - 'A' + 10) << h;
else if(('a' <= c) && (c <= 'f'))
*p += (c - 'a' + 10) << h;
else
return err;
str++;
c = *str;
if (h)
h = 0;
else
{
h = 4;
p++;
*p = 0;
}
}
return result;
}
main.c
#include <stdio.h>
#include "hextools.h"
int main(void)
{
unsigned char s[] = { 0xa0, 0xf9, 0xc3, 0xde, 0x44 };
char *hex = bin2hex(s, sizeof s);
puts(hex);
unsigned char *bin;
bin = hex2bin(hex);
puts(bin2hex(bin, 5));
size_t k;
for(k=0; k<5; k++)
printf("%02X", bin[k]);
putchar('\n');
return 0;
}
char *hexstring = "deadbeef10203040b00b1e50", *pos = hexstring;
unsigned char val[12];
while( *pos )
{
if( !((pos-hexstring)&1) )
sscanf(pos,"%02x",&val[(pos-hexstring)>>1]);
++pos;
}
sizeof(val)/sizeof(val[0]) is redundant!
In main()
{
printf("enter string :\n");
fgets(buf, 200, stdin);
unsigned char str_len = strlen(buf);
k=0;
unsigned char bytearray[100];
for(j=0;j<str_len-1;j=j+2)
{ bytearray[k++]=converttohex(&buffer[j]);
printf(" %02X",bytearray[k-1]);
}
}
Use this
int converttohex(char * val)
{
unsigned char temp = toupper(*val);
unsigned char fin=0;
if(temp>64)
temp=10+(temp-65);
else
temp=temp-48;
fin=(temp<<4)&0xf0;
temp = toupper(*(val+1));
if(temp>64)
temp=10+(temp-65);
else
temp=temp-48;
fin=fin|(temp & 0x0f);
return fin;
}
This is a modified function from a similar question, modified as per the suggestion of https://stackoverflow.com/a/18267932/700597.
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;
}
Two short routines to parse a byte or a word, using strchr().
// HexConverter.h
#ifndef HEXCONVERTER_H
#define HEXCONVERTER_H
unsigned int hexToByte (const char *hexString);
unsigned int hexToWord (const char *hexString);
#endif
// HexConverter.c
#include <string.h> // for strchr()
#include <ctype.h> // for toupper()
unsigned int hexToByte (const char *hexString)
{
unsigned int value;
const char *hexDigits = "0123456789ABCDEF";
value = 0;
if (hexString != NULL)
{
char *ptr;
ptr = strchr (hexDigits, toupper(hexString[0]));
if (ptr != NULL)
{
value = (ptr - hexDigits) << 4;
ptr = strchr (hexDigits, toupper(hexString[1]));
if (ptr != NULL)
{
value = value | (ptr - hexDigits);
}
}
}
return value;
}
unsigned int hexToWord (const char *hexString)
{
unsigned int value;
value = 0;
if (hexString != NULL)
{
value = (hexToByte (&hexString[0]) << 8) |
(hexToByte (&hexString[2]));
}
return value;
}
// HexConverterTest.c
#include <stdio.h>
#include "HexConverter.h"
int main (int argc, char **argv)
{
(void)argc; // not used
(void)argv; // not used
unsigned int value;
char *hexString;
hexString = "2a";
value = hexToByte (hexString);
printf ("%s == %x (%u)\n", hexString, value, value);
hexString = "1234";
value = hexToWord (hexString);
printf ("%s == %x (%u)\n", hexString, value, value);
hexString = "0102030405060708090a10ff";
printf ("Hex String: %s\n", hexString);
for (unsigned int idx = 0; idx < strlen(hexString); idx += 2)
{
value = hexToByte (&hexString[idx]);
printf ("%c%c == %x (%u)\n", hexString[idx], hexString[idx+1],
value, value);
}
return EXIT_SUCCESS;
}
Try the following code:
static unsigned char ascii2byte(char *val)
{
unsigned char temp = *val;
if(temp > 0x60) temp -= 39; // convert chars a-f
temp -= 48; // convert chars 0-9
temp *= 16;
temp += *(val+1);
if(*(val+1) > 0x60) temp -= 39; // convert chars a-f
temp -= 48; // convert chars 0-9
return temp;
}
Here's my version:
/* Convert a hex char digit to its integer value. */
int hexDigitToInt(char digit) {
digit = tolower(digit);
if ('0' <= digit && digit <= '9') //if it's decimal
return (int)(digit - '0');
else if ('a' <= digit && digit <= 'f') //if it's abcdef
return (int)(digit - ('a' - 10));
else
return -1; //value not in [0-9][a-f] range
}
/* Decode a hex string. */
char *decodeHexString(const char *hexStr) {
char* decoded = malloc(strlen(hexStr)/2+1);
char* hexStrPtr = (char *)hexStr;
char* decodedPtr = decoded;
while (*hexStrPtr != '\0') { /* Step through hexStr, two chars at a time. */
*decodedPtr = 16 * hexDigitToInt(*hexStrPtr) + hexDigitToInt(*(hexStrPtr+1));
hexStrPtr += 2;
decodedPtr++;
}
*decodedPtr = '\0'; /* final null char */
return decoded;
}
Could it be simpler?!
uint8_t hex(char ch) {
uint8_t r = (ch > 57) ? (ch - 55) : (ch - 48);
return r & 0x0F;
}
int to_byte_array(const char *in, size_t in_size, uint8_t *out) {
int count = 0;
if (in_size % 2) {
while (*in && out) {
*out = hex(*in++);
if (!*in)
return count;
*out = (*out << 4) | hex(*in++);
*out++;
count++;
}
return count;
} else {
while (*in && out) {
*out++ = (hex(*in++) << 4) | hex(*in++);
count++;
}
return count;
}
}
int main() {
char hex_in[] = "deadbeef10203040b00b1e50";
uint8_t out[32];
int res = to_byte_array(hex_in, sizeof(hex_in) - 1, out);
for (size_t i = 0; i < res; i++)
printf("%02x ", out[i]);
printf("\n");
system("pause");
return 0;
}
For newbies and to improve #Michael's answer here's a full version:
// out needs to be at least len/2+1 bytes long
// length will be returned
int hexStrToBin(char* out, const char *str)
{
int i, len = strlen(str);
for (i = 0; i < len; i++)
{
// Reads str & stores in op
sscanf(str, "%2hhx", &op[i]);
str += 2;
}
return len/2;
}
No. But it's relatively trivial to achieve using sscanf in a loop.
The best way I know:
int hex2bin_by_zibri(char *source_str, char *dest_buffer)
{
char *line = source_str;
char *data = line;
int offset;
int read_byte;
int data_len = 0;
while (sscanf(data, " %02x%n", &read_byte, &offset) == 1) {
dest_buffer[data_len++] = read_byte;
data += offset;
}
return data_len;
}
The function returns the number of converted bytes saved in dest_buffer.
The input string can contain spaces and mixed case letters.
"01 02 03 04 ab Cd eF garbage AB"
translates to dest_buffer containing
01 02 03 04 ab cd ef
and also
"01020304abCdeFgarbageAB"
translates as before.
Parsing stops at the first "error".
Here is a solution to deal with files, which may be used more frequently...
int convert(char *infile, char *outfile) {
char *source = NULL;
FILE *fp = fopen(infile, "r");
long bufsize;
if (fp != NULL) {
/* Go to the end of the file. */
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
bufsize = ftell(fp);
if (bufsize == -1) { /* Error */ }
/* Allocate our buffer to that size. */
source = malloc(sizeof(char) * (bufsize + 1));
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }
/* Read the entire file into memory. */
size_t newLen = fread(source, sizeof(char), bufsize, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
} else {
source[newLen++] = '\0'; /* Just to be safe. */
}
}
fclose(fp);
}
int sourceLen = bufsize - 1;
int destLen = sourceLen/2;
unsigned char* dest = malloc(destLen);
short i;
unsigned char highByte, lowByte;
for (i = 0; i < sourceLen; i += 2)
{
highByte = toupper(source[i]);
lowByte = toupper(source[i + 1]);
if (highByte > 0x39)
highByte -= 0x37;
else
highByte -= 0x30;
if (lowByte > 0x39)
lowByte -= 0x37;
else
lowByte -= 0x30;
dest[i / 2] = (highByte << 4) | lowByte;
}
FILE *fop = fopen(outfile, "w");
if (fop == NULL) return 1;
fwrite(dest, 1, destLen, fop);
fclose(fop);
free(source);
free(dest);
return 0;
}

Resources