Thread: Assigning hex characters dynamically

  1. #1
    Registered User
    Join Date
    Jul 2009
    Posts
    4

    Assigning hex characters dynamically

    Hi,

    I would appreciate if anyone can help with this newbie problem. This is required for me to run a sample C program from the open source GnuTLS package.

    I have a string containing some hexadecimal characters.

    I would like to assign it to another string.

    Code:
    char * hexdata = "4042a55e"
    unsigned char * data;
    The sample program runs if I assign the characters like this:

    Code:
    data[0] = 0x40;
    data[1] = 0x42;
    data[2] = 0xa5;
    data[3] = 0x5e;
    However if I assign it like below, it does not work.

    Code:
    data = hexdata;
    The hexdata can be dynamic for me, so I'm trying to assign it dynamically like this:

    Code:
    for (i = 0; i < 4; i++)
    {
        sprintf(&data[i], "0x%c%c", *hexdata,*(hexdata + 1));
    }
    There must be something wrong with this because the sample program is not working.

    Can you please point out any other way of achieving this:

    Code:
    data[0] = 0x40;
    ....
    Thanks in advance

    Pete

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Are you actually trying to turn eight characters into four? If so, you're going to have to parse the string yourself -- read two characters, figure out what it's "worth" as a hex value, and then assign that value to data[wherever]. (I suppose it's worth mentioning that '4' is not represented with a 4, but with the (almost surely) ASCII value for '4' instead.....)

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    This is wrong for a few reasons:
    Code:
    for (i = 0; i < 4; i++)
    {
        sprintf(&data[i], "0x%c%c", *hexdata,*(hexdata + 1));
    }
    1. you copy 4 bytes "0" "x" "%c" and "%c" starting at data[i].
    2. then you advance one byte and copy four more bytes, three of which are exactly the same
    3. "data" itself does not appear to have any allocated memory, so there is an overflow on the very first sprintf write

    The last point is where we should start.
    Code:
    unsigned char * data;
    "data" is thus an unsigned char pointer, with no memory allocated to it. It is fine to do this
    Code:
    data = hexdata;
    data will now point to hexdata, which is a string literal. However, that means that you cannot make any changes to either one. It would be possible if hexdata was declared this way instead:
    Code:
    char hexdata[] = "4042a55e";
    But in any case, assigning data to hexdata IS NOT the same thing as copying the contents of hexdata to data. That would look something like this:
    Code:
    data = malloc(strlen(hexdata)+1);
    strcpy(data, hexdata);
    Notice memory is allocated to data first.

    As for what you are trying to do in the for() loop, you probably mean something like this:
    Code:
    int len = strlen(hexdata);
    for (i=0;i<len;i++) {
        data[i] = hexdata[i];
    }
    Finally, you should be aware that doing this:
    Code:
    char * hexdata = "4042a55e"
    Does not create a 4-byte string with values 0x40, 0x42, 0xa5, 0x5e! It creates an eight byte string, one for each character. The values for each byte are the ASCII values for the character -- eg. "404" is 0x34, 0x30, 0x34.
    Last edited by MK27; 07-14-2009 at 11:23 AM. Reason: wrong ASCII values!
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Can you explain what you're trying to do and why isn't this working for you?
    Code:
    data = hexdata; /* works just fine for me */

  5. #5
    Registered User
    Join Date
    Jul 2009
    Posts
    4
    Thank you tabstop, MK27 and itCbitC for your replies.

    To explain what I'm trying to do and why isn't this working for me - I'm running a sample program which is part of the open source GnuTLS package. This program has a client which sends a password key as :

    Code:
    typedef struct
      {
        unsigned char *data;
        unsigned int size;
      } gnutls_datum_t;
      
    const gnutls_datum_t key = { (char*) "DEADBEEF", 8 };
    The server sample does the key assignment as follows:

    Code:
      key->data = gnutls_malloc (4);
      key->data[0] = 0xDE;
      key->data[1] = 0xAD;
      key->data[2] = 0xBE;
      key->data[3] = 0xEF;
      key->size = 4;
    I'm trying to find to out how internally it works but right now I do not have the answer.

    What I was trying to do was follow the same way as the server sample but assign key->data dynamically. What I'm trying to figure out is how can I use sscanf or sprintf or any other way to make an assignment similar to

    Code:
    key->data[0] = 0xDE;
    Thanks again

    Pete

  6. #6
    Registered User slingerland3g's Avatar
    Join Date
    Jan 2008
    Location
    Seattle
    Posts
    603
    What do you think this line is doing:

    Code:
       const gnutls_datum_t key = { (char*) "DEADBEEF", 8 };
    IT appears this server code is hard coding those values,clearing them out with gnutls_malloc first, then overwritting the datums as previously assigned.

    A good read on this is found here:

    http://www.gnu.org/software/gnutls/manual/gnutls.pdf

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by IronyOfLife View Post
    What I'm trying to figure out is how can I use sscanf or sprintf or any other way to make an assignment similar to
    Code:
    key->data[0] = 0xDE;
    You don't have to. That is the low-level "no function needed" byte op level that is the essence and fundament of C. If you want to assign an integer value to a byte, any kind of byte (signed, unsigned, char, void, whatever) just do it:
    Code:
    key->data[0] = 0xDE;
    means exactly the same thing as "data[0] = 222". Look:
    Code:
    	unsigned char byte = 0xDE;
    	printf("%d %x",byte,byte);
    d is for decimal, x is for hexadecimal. This will print:
    222 de

    There are no characters with a value greater than 127, tho. If "byte" were signed it would print:
    -34 de
    because signed bytes use "two's complement" to produce positive and negative values (-128 to 127 instead of 0 to 255). Get it? If you did this:
    Code:
    char byte = '4';
    The character '4', NOT the integer value 4, it will print
    52 34

    Assigning to a single char is more simple and straightforward that putting data into and array of chars (ie, a string), which is when you need the string functions.
    Last edited by MK27; 07-14-2009 at 11:25 AM. Reason: wrong ASCII values!
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #8
    {Jaxom,Imriel,Liam}'s Dad Kennedy's Avatar
    Join Date
    Aug 2006
    Location
    Alabama
    Posts
    1,065
    Quote Originally Posted by MK27 View Post
    Code:
    char byte = '4';
    The character '4', NOT the integer value 4, it will print
    20 14

    Assigning to a single char is more simple and straightforward that putting data into and array of chars (ie, a string), which is when you need the string functions.
    In which universe? I'm pretty sure the ASCII value of '4' is 0x34.

  9. #9
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by Kennedy View Post
    In which universe? I'm pretty sure the ASCII value of '4' is 0x34.
    Hey oops! You're right. I was looking at this:

    Table of ASCII Characters

    (so should IronyOfLife, nb!) and got the columns wrong. Sorry. I'll go back and correct those.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  10. #10
    Registered User
    Join Date
    Sep 2008
    Location
    Toronto, Canada
    Posts
    1,834
    Dynamically assign...
    Code:
    	char *hexdata = "4042a55e";
    	char unsigned data[4];   /* caution!!! */
    	int i, temp;
    
    	for (i = 0; hexdata[i]; i += 2) {
    		sscanf(&hexdata[i], "%02x", &temp);
    		data[i / 2] = temp;
    		}

  11. #11
    Registered User
    Join Date
    Jul 2009
    Posts
    4
    Thank you for your suggestions. I tried out the code segment given by nonoob. But there is something lacking in my understanding of the GnuTLS sample program because of which it is not working. I'm going through MK27's posts and will update you with my progress.

    By the way, this forum is the confluence of some very bright minds !

    Thanks

    Pete

  12. #12
    Registered User
    Join Date
    Jul 2009
    Posts
    4
    Finally I could dynamically assign the hexadecimal keys as follows:

    Code:
     
    char * dynamickeys; //Could be any string with hex characters like DEADBEEF
    atohx(key->data,dynamickeys);
    Here is the atohx function I got from the following link:

    No atoh() function in C ( Ascii To Hex )? - Well, Let's Create One

    Code:
      
    char * atohx(char * dst, const char * src)
    {  
     int lsb,msb;
     char * ret;
     ret = dst;
     for(lsb = 0, msb = 0; *src; src += 2)
     { 
      msb = tolower(*src);
      lsb = tolower(*(src + 1));
      msb -= isdigit(msb) ? 0x30 : 0x57;
      lsb -= isdigit(lsb) ? 0x30 : 0x57;
      if((msb < 0x0 || msb > 0xf) || (lsb < 0x0 || lsb > 0xf))
      {
       *ret = 0;
       return NULL;
      }
      *dst++ = (char)(lsb | (msb << 4));  
     }
     *dst = 0;
     return ret;
    }
    Thanks to all for all your suggestions.

  13. #13
    Registered User
    Join Date
    Mar 2009
    Posts
    344
    Unfortunately, this function only works in limited cases. Try passing in a string with an odd length.

  14. #14
    Registered User
    Join Date
    Jun 2009
    Posts
    8
    Use the atoi function? And then just shift bits?

    Code:
    unsigned int hex = atoll(hexdata);
    for (i = 0; i < 4; i++)
        sprintf(data[i], "0x%x", (hex >> ((3-i) * 8)) & 0xff);
    EDIT: changed atoi to atoll...atoi maxes out at 0x7fffffff
    Last edited by newlearner; 07-18-2009 at 01:37 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Hex dump
    By Banana Man in forum C Programming
    Replies: 17
    Last Post: 01-06-2008, 11:03 AM
  2. Replies: 26
    Last Post: 11-30-2007, 03:51 AM
  3. ascii characters video displaying on tv screen
    By deian in forum C Programming
    Replies: 6
    Last Post: 10-12-2004, 09:46 PM
  4. hex to int
    By jyk1981 in forum C Programming
    Replies: 12
    Last Post: 06-24-2004, 11:10 PM
  5. Looking to extract a hex value out of a buffer
    By MMC in forum C Programming
    Replies: 9
    Last Post: 04-12-2002, 01:51 PM