Re: Create a CBitmap from SAFEARRAY
 
On 14 Mar 2007 08:43:17 -0700, dom_perron@hotmail.com wrote:
I developed  a component in .net which I call from an MFC program.
A .net function called in my c++ program  return a safearray ** (wich
is a byte [] in .net).  This  function convert a string of binary data
base64 encoded in a array of byte[].
Here is my .NET implementation:
byte[]      GetDecodedImage(String i_innerText)
{
byte[] base64 = Convert.FromBase64String(i_innerText);
                           return base64;
}
If you are using .NET just for the built-in base-64 decoding class,
you might consider the following C++ code. I adapted the core decoding
engine from a set of C functions at:
  http://www.fourmilab.ch/webtools/base64/
(they have a command line base64 decoder/encoder written in C.)
If you have a base-64 encoded string, and you want to decode it, you
can write e.g.:
// Your base64 encoded input string:
// std::string base64data;
// Buffer to store result
Base64Decoder::Buffer result;
// Do the decoding
BYTE * pBytes = Base64Decoder::Decode( base64data, result );
The Base64Decoder::Decode method takes in input the base64 encoded
string, and a reference to a byte buffer. The method will decode the
input data into the buffer, and will return a pointer to first buffer
byte.
Note that the buffer is a std::vector<BYTE> allocated onto the stack,
so there's no need to delete[] the buffer.
The code follows:
<CODE File="Base64Decoder.h">
//////////////////////////////////////////////////////////////////////////
// FILE: Base64Decoder.h
#pragma once
//
// *** Base-64 Decoder ***
//
// By MrAsm
//
class Base64Decoder
{
public:
    // Byte buffer
    typedef std::vector< BYTE > Buffer;
    //
    // NOTE:
    // Base-64 encoded strings are pure ASCII strings,
    // so they don't need Unicode, and can be stored
    // into std::string.
    //
    // Decode a base64-encoded string, and return the decoded string
    static std::string DecodeString( IN const std::string &
                                     encodedString );
    // Decode a base64-encoded string, and save result into a buffer.
    // Return pointer to first buffer byte.
    static BYTE * Decode( IN const std::string & encodedString,
                          OUT Buffer & out );
    // Decode base64-encoded data read from file, and save result
    // into a buffer.
    // Return pointer to first buffer byte on success.
    // Return NULL on error.
    static BYTE * DecodeFile( IN LPCTSTR szFileName,
                              OUT Buffer & out );
    //
    // IMPLEMENTATION
    //
private:
    static const std::string base64Chars;
    static bool IsBase64( IN unsigned char c ) {
        return (isalnum(c) || (c == '+') || (c == '/'));
    }
    static bool CompactLines( IN LPCTSTR szFileName,
                              OUT std::string & data );
};
//////////////////////////////////////////////////////////////////////////
</CODE>
<CODE File="Base64Decoder.cpp">
//////////////////////////////////////////////////////////////////////////
// FILE: Base64Decoder.cpp
#include "StdAfx.h"
#include "Base64Decoder.h"
const std::string Base64Decoder::base64Chars =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz"
    "0123456789+/";
std::string Base64Decoder::DecodeString( IN const std::string &
encodedString )
{
    //
    // This decoding engine is adapted from:
    //
    // http://www.fourmilab.ch/webtools/base64/
    //
    int in_len = (int) encodedString.size();
    int i = 0;
    int j = 0;
    int in_ = 0;
    unsigned char char_array_4[4], char_array_3[3];
    std::string ret;
    while (in_len-- && ( encodedString[in_] != '=') &&
           IsBase64(encodedString[in_]))
    {
        char_array_4[i++] = encodedString[in_]; in_++;
        if (i ==4)
        {
            for (i = 0; i <4; i++)
                char_array_4[i] = (unsigned char)
                    base64Chars.find(char_array_4[i]);
            char_array_3[0] = (char_array_4[0] << 2) +
                ((char_array_4[1] & 0x30) >> 4);
            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) +
                ((char_array_4[2] & 0x3c) >> 2);
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) +
                char_array_4[3];
            for (i = 0; (i < 3); i++)
                ret += char_array_3[i];
            i = 0;
        }
    }
    if (i)
    {
        for (j = i; j <4; j++)
            char_array_4[j] = 0;
        for (j = 0; j <4; j++)
            char_array_4[j] = (unsigned char)
                base64Chars.find(char_array_4[j]);
        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] &
            0x30) >> 4);
        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) +
            ((char_array_4[2] & 0x3c) >> 2);
        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) +
            char_array_4[3];
        for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
    }
    return ret;
}
// Build a single line from Base64 file content
bool Base64Decoder::CompactLines( IN LPCTSTR szFileName, OUT
std::string & data )
{
    data.clear();
    FILE * file = _tfopen( szFileName, _T("rt") );
    if ( file == NULL )
        return false;
    static const int maxLineChars = 100;
    char line[ maxLineChars + 1 ];
    std::ostringstream os;
    while ( true )
    {
        ZeroMemory( line, sizeof(line) );
        if ( ! fgets( line, maxLineChars, file ) )
        {
            break;
        }
        // Remove ending '\r\n'
        size_t len = strlen(line);
        if ( line[len-2] == '\r' )
            line[len-2] = '\0';
        // Add line
        os << std::string( line );
    }
    fclose( file );
    file = NULL;
    data = os.str();
    return true;
}
BYTE * Base64Decoder::Decode( IN const std::string & encodedString,
OUT Buffer & out )
{
    // Clear output buffer
    out.clear();
    // std::string is a vector of bytes, so we can store
    // decoded stuff into it
    std::string decoded = DecodeString( encodedString );
    // Copy the string content into destination buffer
    out.resize( decoded.length() );
    BYTE * pOutput = &(*out.begin());
    memcpy( pOutput, decoded.c_str(), decoded.length() );
    // Return pointer to destination buffer
    return pOutput;
}
BYTE * Base64Decoder::DecodeFile( IN LPCTSTR szFileName, OUT
std::vector<BYTE> & out )
{
    // Clear output buffer
    out.clear();
    // Check file name
    ASSERT( szFileName != NULL );
    if ( szFileName == NULL )
        return NULL;
    // Compact input file lines into a single base64 string
    std::string base64data;
    if ( ! CompactLines( szFileName, base64data ) )
        return NULL;
    // Decode into buffer
    return Decode( base64data, out );
}
//////////////////////////////////////////////////////////////////////////
</CODE>
MrAsm