Convert mysql blob into hex


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 13 of 13

Thread: Convert mysql blob into hex

Hybrid View

  1. #1
    Join Date
    Sep 2009
    Posts
    10

    Convert mysql blob into hex

    Hello!
    My program stores images in mysql blob field.

    I can retrieve it into char* and I know it's length.

    To make a backup of that data I need to convert it to something like this:

    0x234cb6244db7264fb92750ba2e57c12f58c2315ac4335cc62b5bc729

    I tried something like this:
    Code:
     char* szStop;
     strtol( str, &szStop, 16 );
    std::cout << szStop;
    But the output is not what I wanted. How do I convert it properly?

    Thanks in advance!

    Leonti

  2. #2
    Join Date
    Nov 2003
    Posts
    4,118
    strtoll might help a little bit if the blob contains up to 8 bytes. However, if the blob is bigger than that there's no standard function that can convert it into a single huge hex number. Either break it down into individual chunks of 8 bytes, or retain it as a char string. That is, create another usigned char array and copy the original blob to that array.
    Danny Kalev

  3. #3
    Join Date
    Sep 2009
    Posts
    10
    Thank you for answering!
    So I guess I have to do this for every character in my string, right?
    I found similar function on the internet.
    Original function uses sprintf_s and somehow it's not in my system.
    So I tried to modify it for using with strtol.

    Right now I get:
    error: invalid conversion from ‘const char’ to ‘const char*’
    How do I fix this?
    Code:
    std::string toString(const char* data, const int datasize)
    {
    std::string output;
    char ch[3];
    for(int i = 0; i < datasize; ++i)
    {
    strtol( data[i], &ch, 16 );
    output += ch;
    }
    return output;
    }
    Leonti

  4. #4
    Join Date
    Oct 2007
    Posts
    369
    If it is a matter of converting a block-of-bytes into a printable character string, use something like this
    Code:
    #include <sstring>
    std::string toString(const char* data, const int datasize)
    {
        std::ostring out;
        out << std::hex;
        for (int i=0; i<datasize; ++i)
        {
            out << (unsigned int)data[i];
        }
        return out.str();
    }

  5. #5
    Join Date
    Sep 2009
    Posts
    10
    hendrixj, thank you! I'm getting close.

    Right now the problem is that string made from my program is different from that made from mysqldump.

    This is my string:
    0x234cffffffb6244dffffffb7264fffffffb92750ffffffba2e57ffffffc12f58ffffffc2315affffffc4335c ffffffc62b5bffffffc7295[...]
    And this is mysqldump/phpMyAdmin one:
    0x234cb6244db7264fb92750ba2[...]
    It's identical with the exception of too many 'f'. How do I get rid of those "extra" 'f' symbols?

    Leonti

  6. #6
    Join Date
    Nov 2003
    Posts
    4,118
    There are three issues here. First, replace
    Code:
    strtol( data[i], &ch, 16 );
    With:
    Code:
    strtol( data[i], ch, 16 );
    With respect to the latter example, the problem is that you're casting char to unsigned int, which means that three bytes of each int contain binary zeroes. You need to do something quite different here: cast every quartet (set of four bytes) into unsigned int, not every byte:
    Code:
    for (int i=0; i<datasize; i+=sizeof(unsigned int))
        {
         out << *((unsigned int*) (&data[i])); //cast to pointer to unsigned, then dereference
        }
    return out.str();
    Danny Kalev

  7. #7
    Join Date
    Oct 2007
    Posts
    369
    Danny's suggestion works as long as the datasize is evenly divisible by 4.
    If not, try taking my code an casting to unsigned char. All the "f"s occur because a "negative char" (the most significant bit is set, i.e., for anything over 127) is being converted to a negative integer (the 1 in the most significant bit is being expanded into the unused 3 bytes).

    finally, after declaring out, use "out.width(2)" to set the width of integers to two.

  8. #8
    Join Date
    Oct 2007
    Posts
    369
    In that last post, I suggested you cast to an unsigned char. That was dumb. Leave the cast as an unsigned int. I did a little test program to hopefully find my other silly mistakes. Here it is :
    [Code]
    #include <iostream>
    #include <sstream>
    using namespace std;

    string toString(char* data, int size)
    {
    ostringstream out;
    out.width(2);
    out << hex;
    for (int i=0; i<5; i++)
    {
    out << (unsigned int)data[i];
    }
    return out.str();
    }

    int main()
    {
    char test[5] = {'0', 'b', 'c', 'd', 'e'};

    cout << toString(test, 5);

    return 0;
    }

    [\Code]

  9. #9
    Join Date
    Dec 2007
    Posts
    401
    Code:
    #include <string>
    #include <sstream>
    #include <iomanip>
    
    std::string to_hex_string( const char* data, std::size_t datasize )
    {
        std::ostringstream stm ;
        stm << "0x" << std::hex << std::noshowbase ;
    
        for( std::size_t i = 0 ; i < datasize ; ++i )
            stm << std::setw(2) << std::setfill('0') << int( (unsigned char)data[i] ) ;
    
        return stm.str();
    }

  10. #10
    Join Date
    Sep 2009
    Posts
    10
    Thank you, guys!
    It's working now! String is a perfect match!
    You saved me a lot of time. Now I will have to understand how it actually works :)

    Leonti

  11. #11
    Join Date
    Nov 2003
    Posts
    4,118
    Quote Originally Posted by Leonti View Post
    Thank you, guys!
    It's working now! String is a perfect match!
    You saved me a lot of time. Now I will have to understand how it actually works :)

    Leonti
    As Hendrixj noted, my solution assumes that the size of the blob is a multiple of 4. If it isn't you need to check it before the loop.

    Also, which solution did you finally implement? Just for the sake of future members who might ask the same question.
    Danny Kalev

  12. #12
    Join Date
    Sep 2009
    Posts
    10
    I tried hendrixj solution and it still gave me 'f'.
    My data in blob is probably dividable by 4, so your function probably would work but I went with vijayan 's solution because I understand what's going on (more or less) in the code and it works perfectly.

    Leonti

  13. #13
    Join Date
    Dec 2007
    Posts
    401
    my solution assumes that the size of the blob is a multiple of 4. If it isn't you need to check it before the loop.
    in addition, you also need to:

    a. take care of endianness; for instance the code will give incorrect output on an i386 or amd64 machine. see: http://www.ibm.com/developerworks/ai...ml?ca=drs-#end

    b. take care of alignment requirements. see: http://www.ibm.com/developerworks/library/pa-dalign/

    It is possible to do this, and for a large blob the code could well be faster. but writing correct, portable code which casts a char* to an unsigned int* and uses the result of the cast needs to be written with a lot of care, paying attention to a number of low-level details. for example:
    Code:
    #include <type_traits> // C++0X
    #include <string>
    #include <sstream>
    #include <iomanip>
    #include <algorithm>
    #include <limits>
    #include <cassert>
    #include <iostream>
    
    // verify that the byte is an 8-bit octet
    // C++0x, with C++98, use BOOST_STATIC_ASSERT
    // http://www.boost.org/doc/libs/1_40_0/doc/html/boost_staticassert.html#boost_staticassert.intro
    static_assert( std::numeric_limits<unsigned char>::digits == 8, "a byte must be an octet" ) ;
    
    enum
    {
      ISIZE = sizeof(unsigned int),
    
      ALIGNMENT = std::alignment_of<unsigned int>::value // C++0X
      // with C++98, use: __alignof__ (GCC), __alignof (microsoft)
    } ;
    
    // would work only on big-endian or little-endian archtectures,
    // does not handle middle-endian or mixed-endian architectures
    inline unsigned int make_big_endian( unsigned int num )
    {
        union int_bytes { unsigned int number ; unsigned char bytes[ISIZE] ; };
    
        static int_bytes probe = { 1U } ; //
        // assert that the architecture is either big-endian or little-endian
        assert( "endianess of this architecture is supported" &&
                ( probe.bytes[0] || probe.bytes[ISIZE-1] ) ) ;
        static bool little_endian = probe.bytes[0] == 1U ;
    
        int_bytes number_bytes = { num } ;
        if( little_endian ) std::reverse( number_bytes.bytes, number_bytes.bytes+ISIZE ) ;
    
        return number_bytes.number ;
    }
    
    std::string to_hex_string( const char* data, std::size_t data_size )
    {
    
        std::ostringstream stm ;
        stm << "0x" << std::hex << std::noshowbase ;
    
        union address_probe
        {
            const char* pointer ;
            std::size_t value ;
        };
        address_probe probe = { data } ;
    
        // process bytes one by one till we get to an address that meets
        // the alignment requirement for unsigned int
        std::size_t lead_bytes = (ALIGNMENT - probe.value &#37; ALIGNMENT) % ALIGNMENT ;
        for( std::size_t i = 0 ; i < lead_bytes ; ++i )
            stm << std::setw(2) << std::setfill('0') << int( (unsigned char)data[i] ) ;
        data += lead_bytes ;
    
        if( data_size >  lead_bytes )
        {
             // process sizeof(unsigned int) bytes at a time as a single unsigned int
             const unsigned int* idata = (const unsigned int*)( data ) ;
             for( data_size -=  lead_bytes ; data_size >= ISIZE ; ++idata )
             {
               stm << std::setw( ISIZE*2 ) << std::setfill('0')
                   << make_big_endian(*idata) ; // reverse the bytes if little-endian
               data_size -= ISIZE ;
               data += ISIZE ;
             }
    
             // process the trailing bytes one by one till end of data
             for( std::size_t i = 0 ; i < data_size ; ++i )
                 stm << std::setw(2) << std::setfill('0') << int( (unsigned char)data[i] ) ;
        }
    
        return stm.str();
    }
    
    // a simple test case
    int main()
    {
        const char test[] = " 012\b\n\r\t\377\277\177HFFFfgfgfgfGFFFFFFFF\b\n\r\t\377\277\177!!" ;
        std::cout << to_hex_string( test+3, sizeof(test)-3 ) << '\n' ;
    }
    and even this does not take care of all processor architectures.
    Last edited by vijayan; 09-28-2009 at 02:32 AM. Reason: code corrected

Similar Threads

  1. Convert XML Elements values from Hex
    By togesu in forum .NET
    Replies: 1
    Last Post: 12-19-2006, 12:51 PM
  2. Replies: 4
    Last Post: 06-02-2006, 06:09 AM
  3. convert hex string to long
    By David Chu in forum .NET
    Replies: 1
    Last Post: 11-25-2002, 03:01 PM
  4. Need to Convert a Hex string to a Hex number
    By Dan Fergus in forum .NET
    Replies: 3
    Last Post: 08-23-2001, 02:39 PM
  5. Convert to Hex
    By Sarel j Smit in forum Database
    Replies: 1
    Last Post: 05-24-2001, 11:35 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center