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