Question

I'm trying to implement a function which returns a string of hex values. I print the hex values out using this function:

void print_hex(unsigned char *hash, const hashid type) {

    int i;
    for (i = 0; i < mhash_get_block_size(type); i++) {
        printf("%.2x", hex[i]);
    }
    printf("\n");
}

This outputs some hex value, e.g. 71c092a79cf30c4c7e7baf46a4af3c78cedec9ae3867d1e2600ffc39d58beaf2

How can I modify this function so that it returns a string? i.e.

unsigned char *get_hash_str(unsigned char *hash, const hashid type) { /* ?? */ }

(The goal being to compare the 2 values later)

Was it helpful?

Solution

char * print_hex(const unsigned char *hash, const hashid type)
{
    const char lookupTable[]="0123456789abcdef";
    const size_t hashLength=mhash_get_block_size(type);
    size_t i;
    char * out=malloc(hashLength*2+1);
    if(out==NULL)
        return NULL;
    for (i = 0; i < hashLength; i++)
    {
        out[i*2]=lookupTable[hash[i]>>4];
        out[i*2+1]=lookupTable[hash[i]&0xf];
    }
    out[hashLength*2]=0;
    return out;
}

Obviously the caller is responsible for freeing the returned string.

Still, as @K-Ballo correctly said in his answer, you don't need to convert to string form two hashes to compare them, all you need in that case is just a memcmp.

int compare_hashes(const unsigned char * hash1, const hashid hash1type, const unsigned char * hash2, const hashid hash2type)
{
    if(hash1type!=hash2type)
        return 0;
    return memcmp(hash1, hash2, mhash_get_block_size(hash1type))==0;
}

OTHER TIPS

How can I modify this function so that it returns a string?

You can print to a string variable using sprintf. I assume the hash size is fixed, so you know the size of your string would be number-of-chars-in-hash * 2 + 1. How to return that information is a typical problem in C, you can either return a malloced string that the user must then remember to free, or return a static string that will get replaced with the next call to the function (and makes the function non-reentrable). Personally I tend to avoid returning strings, instead having the function take a char* destination and a size.

(The goal being that I can compare the 2 values later)

Just compare the two hash variables in its raw form, you don't need strings for that.

The sprintf() function does the same thing as printf(), except that it "prints" to a char buffer. With that your function could look like this:

void sprint_hex(char *outbuf, unsigned char *hash, const hashid type) {
    int i;
    for (i = 0; i < mhash_get_block_size(type); i++) {
        sprintf(outbuf, "%.2x", hex[i]);
        outbuf += 2;
    }
}

Note that this assumes that a buffer of suitable size is passed in as outbuf.

Have the user pass in the buffer to be written to, along with the size. Obviously, the function has to be renamed. Even this is a bit generic; it should perhaps be format_hash_to_hex_string() because of the hashid parameter.

int format_hex_string(unsigned char const *hash, hashid type, char *buffer, size_t buflen)
{
    size_t n = mhash_get_block_size(type);
    if (buflen < 2 * n + 1)
        return -1;
    for (size_t i = 0; i < n; i++)
        sprintf(&buffer[2*i], "%.2X", hash[i]);
    return 0;
}

Or, if you trust your users to provide a big enough buffer:

format_hex_string(unsigned char const *hash, hashid type, char *buffer)
{
    size_t n = mhash_get_block_size(type);
    for (size_t i = 0; i < n; i++)
        sprintf(&buffer[2*i], "%.2X", hash[i]);
}

Or if you prefer bit twiddling (which probably is quicker than calling sprintf()):

int format_hex_string(unsigned char const *hash, hashid type, char *buffer, size_t buflen)
{
    static char const hexdigits[] = "0123456789ABCDEF";
    size_t n = mhash_get_block_size(type);
    if (buflen < 2 * n + 1)
        return -1;
    for (size_t i = 0; i < n; i++)
    {
        *buffer++ = hexdigits[hash[i] >>  4];
        *buffer++ = hexdigits[hash[i] & 0xF];
    }
    *buffer = '\0';
    return 0;
}

To justify the generic name, it would be better to replace the hashid type parameter with a simple length (and you could then reasonably assume that the programmer knows that the buffer length must be at least 2 times the hash length):

int format_hex_string(unsigned char const *binbuffer, size_t binlen, char *hexbuffer)
{
    static char const hexdigits[] = "0123456789ABCDEF";
    for (size_t i = 0; i < binlen; i++)
    {
        *hexbuffer++ = hexdigits[binbuffer[i] >>  4];
        *hexbuffer++ = hexdigits[binbuffer[i] & 0xF];
    }
    *hexbuffer = '\0';
}

This now is a general purpose function. And you could wrap it to specialize it for your hash formatting if you wanted to; the wrapper might save you writing a few calls to your mhash_get_block_size() function.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top