0

I want to convert hexadecimal strings like:

FE2A8D0000CA372D4F461B1D9A1883A32F018823FFFF60D30000484200000D0A0F270300030006000000B0040307000356A3

Into this format:

const char msg[] = {0xFE, 0x2A, 0x8D, 0x00, 0x00, 0xCA, 0x37, 0x2D, 0x4F,
0x46, 0x1B, 0x1D, 0x9A, 0x18, 0x83, 0xA3, 0x2F, 0x01, 0x88, 0x23, 0xFF,
0xFF, 0x60, 0xD3, 0x00, 0x00, 0x48, 0x42, 0x00, 0x00, 0x0D, 0x0A, 0x0F,
0x27, 0x03, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0xB0, 0x04, 0x03,
0x07, 0x00, 0x03, 0x56, 0xA3};

At the moment, I use regex in Notepad++, and works well. This is the regex:

find: ([a-z0-9]{2})
replace with: \, 0x\1
(then I remove the first ',')

I'm coding in C, I have tried using regex but I can't get it working. How should I use regex for this?

A solution without regex is also fine.

CSᵠ
  • 10,049
  • 9
  • 41
  • 64
alexms
  • 1

4 Answers4

0

for example

const char * demo = "FE2A8D0000CA372D4F461B1D9A1883A32F018823FFFF60D30000484200000D0A0F270300030006000000B0040307000356A3";
int len = strlen(demo);
int i;
char ** msg = (char**) malloc(sizeof(char*) * len / 2);
for(i = 0; i < len / 2; i++) {
    msg[i] = (char*) malloc(sizeof(char) * 5);
    strncpy(msg[i], "0x", 2);
    strncpy(msg[i] + 2, demo + i * 2, 2);
    strncpy(msg[i] + 4, "\0", 1);
}
K.Juce
  • 253
  • 1
  • 6
  • Possible ameliorations : avoid casting the result of `malloc`, use `calloc` when allocating memory to an array, replace `demo + i` by `demo[i]`, declare `i` within the for loop like `for (int i = 0 ......)` ? – Badda Jun 06 '17 at 11:53
  • Why to use `calloc` when you allocate memory to an array? Can you allocate memory to something else which is not array? Why avoid casting? *please don't say only argument that `void *` is automatically promoted* – unalignedmemoryaccess Jun 06 '17 at 11:54
  • @tilz0R [Do I cast the result of malloc?](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – Stargateur Jun 06 '17 at 12:03
0

May be following code will fulfill the requirement:

 #include <stdio.h>
 #include <string.h>

 void printHex(char data[])
 {
     int i,j;
     char temp[] = "0x00";
     int count = strlen(data)/2;

     for(i=0, j=0; i<count;i++, j+=2)
     {
         temp[2] = data[j];
         temp[3] = data[j+1];
         printf("%s, ",temp);
     }
 }

 int main()
 {
     char data[]="FE2A8D0000CA372D4F461B1D9A1883A32F018823FFFF60D30000484200000D0A0F270300030006000000B0040307000356A3";
     printHex(data);
     return 0;
 }
cse
  • 4,066
  • 2
  • 20
  • 37
  • It is better (nicer, in fact) to use `void printHex(char* data)` instead fo `void printHex(char data[])` – unalignedmemoryaccess Jun 06 '17 at 11:56
  • Any specific reason? I think it is a matter of coding style. It doesn't changes anything. – cse Jun 06 '17 at 11:59
  • Yes, that's why I said *nicer* :) – unalignedmemoryaccess Jun 06 '17 at 12:04
  • If it is so then, I'm not agree with you ;). Generally people get scared when they encounter a pointer in the code. So, I prefer to eliminate them :). By the way it varies from person to person and as stated previously that: It is a matter of choice. – cse Jun 06 '17 at 12:13
  • It is not true :) Using empty array can mean different things to people and not pointer specific. Pointers should be used in this situation at all. It is understandable. – unalignedmemoryaccess Jun 06 '17 at 12:17
0

Your question is a bit unclear, but assuming you just want to fill a char array with binary data from a hex string at runtime, something like this will do it:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char *buf = "FE2A8D0000CA372D4F461B1D9A1883A32F018823FFFF60D30000484200000D0A0F270300030006000000B0040307000356A3";

static unsigned char hexNibble(const char *str)
{
    unsigned char hex = *str;
    if (hex >= 'a' && hex <='f')
    {
        hex -= ('a' - 10);
    }
    else if (hex >= 'A' && hex <= 'F')
    {
        hex -= ('A' - 10);
    }
    else if (hex >= '0' && hex <= '9')
    {
        hex -= '0';
    }
    else
    {
        hex = 0;
    }
    return hex;
}

static size_t createCharArrayFromHexString(char *result[], const char *str)
{
    size_t len = strlen(str);
    if (!len) return 0;
    size_t bytes = len / 2;
    int mostSignificantNibble = len % 2;
    size_t size = bytes + mostSignificantNibble;
    *result = malloc(size);
    char *out = *result;
    const char *in = str;
    if (mostSignificantNibble)
    {
        *out++ = hexNibble(in++);
    }
    while (bytes)
    {
        *out = hexNibble(in++);
        *out <<= 4;
        *out++ |= hexNibble(in++);
        --bytes;
    }
    return size;
}

int main(void) {
    int value = 0;
    char *converted;

    size_t convertedSize = createCharArrayFromHexString(&converted, buf);

    for (int i = 0; i < convertedSize; ++i)
    {
        printf( "0x%02hhx\n", converted[i]);
    }

    free(converted);
}

Inside the main loop of createCharArrayFromHexString(), you could as well use sscanf() for converting as is already in the comments to your question.

You can greatly simplify this code if you can guarantee there's always an even number of characters in your hex input. See the code running here

0

The program in the box below contains the function const char * convert(const char * inb,int idx) that creates a buffer containing the data formatted as you require.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define HEADER1_TEXT "const char msg_"

#define HEADER2_LEN     6   //The number of digits in the costants name msg_nnnn we want

#define HEADER3_TEXT "[] = {"
#define HEADERLENGTH   (strlen(HEADER1_TEXT)+HEADER2_LEN+strlen(HEADER3_TEXT))

#define FOOTER "\n};\n"
#define FOOTERLENGTH    (strlen(FOOTER))

#define INDENT "\n    "
#define INDENTLENGTH    (strlen(INDENT))

#define ITEMxROW        8
#define HEXFIELDLEN     6           // "0xnn, "
#define ROWLEN          (INDENTLENGTH + (ITEMxROW * HEXFIELDLEN))

const char * convert(const char * inb,int idx);

const char * convert(const char * inb,int idx)
{
    char * outb = NULL;
    unsigned int l,rl=0,j;

    l=strlen(inb);
    if (l) {
        j=l/2*HEXFIELDLEN - 1;      //The char used to convert all digit with the format: "0xnn, "
        rl=(j+ROWLEN)/ROWLEN;       //Row number
        j=j + rl*(INDENTLENGTH+1);  // +1 The CR
        j=j + HEADERLENGTH + FOOTERLENGTH;

        outb = malloc(j+11); //+ 11 because the dimension is not correctly computed!!! :(
        memset(outb,0,j+1);

        if (outb!=NULL) {
            strcpy(outb, HEADER1_TEXT);

            sprintf(outb+strlen(outb),"%0" STR(HEADER2_LEN) "d",idx);

            strcat(outb,HEADER3_TEXT);

            rl=0;
            for(j=0;j<l;j+=2) {
                if (j)
                    strcat(outb,", ");

                if ( (rl + HEADER2_LEN) > ROWLEN) {
                    rl=0;
                }

                if (!rl) {
                    rl=INDENTLENGTH;
                    strcat(outb,INDENT);
                }

                strcat(outb,"0x");
                strncat(outb,inb+j,2);

                rl+=HEXFIELDLEN;
            }
        }
    }

    return outb;
}

int main(int argc, char *argv[])
{
    int i,retval=0;
    char * buff=NULL;

    if (argc<2) {
        printf("Usage: %s hex-string [hex-string2] [...] [hex-stringn]\n",basename(argv[0]));
        return 1;
    }

    for(i=1; i<argc; i++) {
        buff=convert(argv[i],i);

        if (buff!=NULL) {
            strcat(buff,FOOTER);
            printf("%s\n",buff);
            free(buff);
        } else {
            retval=1;
            break;
        }
    }

    return retval;
}

The program-main calls the function convert sending it the prompt parameters. To decode your string you have to compile the code (for example as convert) and then you have to run it from the system prompt using the string[s] to convert as parameter[s].

sysprompt: convert FE2A8D0000CA372D4F461B1D9A1883A32F018823FFFF60D30000484200000D0A0F270300030006000000B0040307000356A3 

the output will be:

const char msg_000001[] = {
    0xFE, 0x2A, 0x8D, 0x00, 0x00, 0xCA, 0x37, 0x2D, 
    0x4F, 0x46, 0x1B, 0x1D, 0x9A, 0x18, 0x83, 0xA3, 
    0x2F, 0x01, 0x88, 0x23, 0xFF, 0xFF, 0x60, 0xD3, 
    0x00, 0x00, 0x48, 0x42, 0x00, 0x00, 0x0D, 0x0A, 
    0x0F, 0x27, 0x03, 0x00, 0x03, 0x00, 0x06, 0x00, 
    0x00, 0x00, 0xB0, 0x04, 0x03, 0x07, 0x00, 0x03, 
    0x56, 0xA3
};

You may convert more strings. For example:

sysprompt: convert FE55ACA220 56ABFC 4587ABFD

the output will be:

const char msg_000001[] = {
    0xFE, 0x55, 0xAC, 0xA2, 0x20
};

const char msg_000002[] = {
    0x56, 0xAB, 0xFC
};

const char msg_000003[] = {
    0x45, 0x87, 0xAB, 0xFD
};

P.S.: In the convert functions there's a piece of code that computes the dimension of the buffer to be used (and allocated) for the conversion. This piece of code is not complitely correct, execuse me! I think you can solve this problem!

Sir Jo Black
  • 2,024
  • 2
  • 15
  • 22