You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
9.4 KiB
381 lines
9.4 KiB
// BinHex.cpp: implementation of the CBinHex class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "BinHex.h"
|
|
#include "BstrDebug.h"
|
|
|
|
// These characters are the legal digits, in order, that are
|
|
// used in Base64 encoding
|
|
//
|
|
|
|
const WCHAR rgwchBase64[] =
|
|
L"ABCDEFGHIJKLMNOPQ"
|
|
L"RSTUVWXYZabcdefgh"
|
|
L"ijklmnopqrstuvwxy"
|
|
L"z0123456789!*";
|
|
|
|
const char rgwchBase64ASCII[] =
|
|
"ABCDEFGHIJKLMNOPQ"
|
|
"RSTUVWXYZabcdefgh"
|
|
"ijklmnopqrstuvwxy"
|
|
"z0123456789!*";
|
|
|
|
|
|
CBinHex::CBinHex()
|
|
{
|
|
unsigned char i;
|
|
//
|
|
// Initialize our decoding array
|
|
//
|
|
memset(m_decodeArray, BBAD, 256);
|
|
for (i = 0; i < 64; i++)
|
|
{
|
|
WCHAR wch = rgwchBase64[i];
|
|
m_decodeArray[wch] = i;
|
|
}
|
|
}
|
|
|
|
// This function takes IN a single-char buffer, and puts the binhex
|
|
// output into a bstr -- in the bstr, it's ASCII string
|
|
//
|
|
// Function name : ToBase64
|
|
// Description :
|
|
// Return type : HRESULT
|
|
// Argument : LPVOID pv
|
|
// Argument : ULONG cbSize
|
|
// Argument : char prepend
|
|
// Argument : BSTR* pbstr
|
|
//
|
|
HRESULT CBinHex::ToBase64ASCII(LPVOID pv, UINT cbSize, char prepend, char ivecnpad[9], BSTR* pbstr)
|
|
//
|
|
// Encode and return the bytes in base 64
|
|
//
|
|
{
|
|
UINT cb = cbSize, cbSafe, cchNeeded, cbNeeded, i;
|
|
HRESULT hr = S_OK;
|
|
|
|
*pbstr = NULL;
|
|
if (cb % 3)
|
|
cbSafe = cb + 3 - (cb % 3); // For padding
|
|
else
|
|
cbSafe = cb;
|
|
// cbSafe is now a multiple of 3
|
|
|
|
cchNeeded = (cbSafe*4/3); // 3 normal bytes --> 4 chars
|
|
cbNeeded = cchNeeded;
|
|
|
|
if (prepend != 0)
|
|
{
|
|
if (ivecnpad != NULL)
|
|
*pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2+18); // ivec & kv
|
|
else
|
|
*pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2); // just kv
|
|
}
|
|
else
|
|
*pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded);
|
|
if (*pbstr)
|
|
{
|
|
BYTE* pb = (BYTE*)pv;
|
|
char* pch = (char*)*pbstr;
|
|
int cchLine = 0;
|
|
|
|
if (prepend != 0)
|
|
{
|
|
*pch++ = (char) prepend;
|
|
if (ivecnpad != NULL)
|
|
{
|
|
for (i = 0; i < 9; i++)
|
|
*pch++ = (char) ivecnpad[i];
|
|
}
|
|
}
|
|
//
|
|
// Main encoding loop
|
|
//
|
|
while (cb >= 3)
|
|
{
|
|
BYTE b0 = ((pb[0]>>2) & 0x3F);
|
|
BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F);
|
|
BYTE b2 = ((pb[1]&0x0F)<<2) | ((pb[2]>>6) & 0x03);
|
|
BYTE b3 = ((pb[2]&0x3F));
|
|
|
|
*pch++ = rgwchBase64ASCII[b0];
|
|
*pch++ = rgwchBase64ASCII[b1];
|
|
*pch++ = rgwchBase64ASCII[b2];
|
|
*pch++ = rgwchBase64ASCII[b3];
|
|
|
|
pb += 3;
|
|
cb -= 3;
|
|
|
|
}
|
|
|
|
if (cb==0)
|
|
{
|
|
// nothing to do
|
|
}
|
|
else if (cb==1)
|
|
{
|
|
BYTE b0 = ((pb[0]>>2) & 0x3F);
|
|
BYTE b1 = ((pb[0]&0x03)<<4) | 0;
|
|
*pch++ = rgwchBase64ASCII[b0];
|
|
*pch++ = rgwchBase64ASCII[b1];
|
|
*pch++ = '$';
|
|
*pch++ = '$';
|
|
}
|
|
else if (cb==2)
|
|
{
|
|
BYTE b0 = ((pb[0]>>2) & 0x3F);
|
|
BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F);
|
|
BYTE b2 = ((pb[1]&0x0F)<<2) | 0;
|
|
*pch++ = rgwchBase64ASCII[b0];
|
|
*pch++ = rgwchBase64ASCII[b1];
|
|
*pch++ = rgwchBase64ASCII[b2];
|
|
*pch++ = '$';
|
|
}
|
|
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
GIVEAWAY_BSTR(*pbstr);
|
|
return hr;
|
|
}
|
|
|
|
// This function takes IN a single-char buffer, and puts the binhex
|
|
// output into a bstr, but using only ASCII chars
|
|
//
|
|
// Function name : ToBase64
|
|
// Description :
|
|
// Return type : HRESULT
|
|
// Argument : LPVOID pv
|
|
// Argument : ULONG cbSize
|
|
// Argument : char prepend
|
|
// Argument : BSTR* pbstr
|
|
//
|
|
HRESULT CBinHex::ToBase64(LPVOID pv, UINT cbSize, char prepend, char ivecnpad[9], BSTR* pbstr)
|
|
//
|
|
// Encode and return the bytes in base 64
|
|
//
|
|
{
|
|
UINT cb = cbSize, cbSafe, cchNeeded, cbNeeded, i;
|
|
HRESULT hr = S_OK;
|
|
|
|
*pbstr = NULL;
|
|
if (cb % 3)
|
|
cbSafe = cb + 3 - (cb % 3); // For padding
|
|
else
|
|
cbSafe = cb;
|
|
// cbSafe is now a multiple of 3
|
|
|
|
cchNeeded = (cbSafe*4/3); // 3 normal bytes --> 4 chars
|
|
cbNeeded = cchNeeded * sizeof(WCHAR);
|
|
|
|
if (prepend != 0)
|
|
{
|
|
if (ivecnpad != NULL)
|
|
*pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2+18); // ivec & kv
|
|
else
|
|
*pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2); // just kv
|
|
}
|
|
else
|
|
*pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded);
|
|
if (*pbstr)
|
|
{
|
|
BYTE* pb = (BYTE*)pv;
|
|
WCHAR* pch = *pbstr;
|
|
int cchLine = 0;
|
|
|
|
if (prepend != 0)
|
|
{
|
|
*pch++ = (WCHAR) prepend;
|
|
if (ivecnpad != NULL)
|
|
{
|
|
for (i = 0; i < 9; i++)
|
|
*pch++ = (WCHAR) ivecnpad[i];
|
|
}
|
|
}
|
|
//
|
|
// Main encoding loop
|
|
//
|
|
while (cb >= 3)
|
|
{
|
|
BYTE b0 = ((pb[0]>>2) & 0x3F);
|
|
BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F);
|
|
BYTE b2 = ((pb[1]&0x0F)<<2) | ((pb[2]>>6) & 0x03);
|
|
BYTE b3 = ((pb[2]&0x3F));
|
|
|
|
*pch++ = rgwchBase64[b0];
|
|
*pch++ = rgwchBase64[b1];
|
|
*pch++ = rgwchBase64[b2];
|
|
*pch++ = rgwchBase64[b3];
|
|
|
|
pb += 3;
|
|
cb -= 3;
|
|
|
|
}
|
|
|
|
if (cb==0)
|
|
{
|
|
// nothing to do
|
|
}
|
|
else if (cb==1)
|
|
{
|
|
BYTE b0 = ((pb[0]>>2) & 0x3F);
|
|
BYTE b1 = ((pb[0]&0x03)<<4) | 0;
|
|
*pch++ = rgwchBase64[b0];
|
|
*pch++ = rgwchBase64[b1];
|
|
*pch++ = L'$';
|
|
*pch++ = L'$';
|
|
}
|
|
else if (cb==2)
|
|
{
|
|
BYTE b0 = ((pb[0]>>2) & 0x3F);
|
|
BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F);
|
|
BYTE b2 = ((pb[1]&0x0F)<<2) | 0;
|
|
*pch++ = rgwchBase64[b0];
|
|
*pch++ = rgwchBase64[b1];
|
|
*pch++ = rgwchBase64[b2];
|
|
*pch++ = L'$';
|
|
}
|
|
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
GIVEAWAY_BSTR(*pbstr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CBinHex::PartFromBase64(LPSTR lpStr, BYTE *output, ULONG *numOutBytes)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!output) return E_INVALIDARG;
|
|
|
|
//
|
|
// Loop over the input buffer until we get numOutBytes in output
|
|
//
|
|
ULONG bCurrent = 0; // what we're in the process of filling up
|
|
int cbitFilled = 0; // how many bits in it we've filled
|
|
ULONG numOut = 0;
|
|
BYTE* pb = (BYTE*) output; // current destination (not filled)
|
|
|
|
for (CHAR* pch=lpStr; *pch && numOut < *numOutBytes; pch++)
|
|
{
|
|
CHAR ch = *pch;
|
|
//
|
|
// Have we reached the end?
|
|
//
|
|
if (ch=='$')
|
|
break;
|
|
//
|
|
// How much is this character worth?
|
|
//
|
|
BYTE bDigit = m_decodeArray[ch];
|
|
if (bDigit==BBAD)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
//
|
|
// Add in its contribution
|
|
//
|
|
bCurrent <<= 6;
|
|
bCurrent |= bDigit;
|
|
cbitFilled += 6;
|
|
//
|
|
// If we've got enough, output a byte
|
|
//
|
|
if (cbitFilled >= 8)
|
|
{
|
|
ULONG b = (bCurrent >> (cbitFilled-8)); // get's top eight valid bits
|
|
*pb++ = (BYTE)(b&0xFF); // store the byte away
|
|
cbitFilled -= 8;
|
|
numOut++;
|
|
}
|
|
} // for
|
|
|
|
_ASSERT(numOut <= *numOutBytes);
|
|
|
|
if (hr!=S_OK)
|
|
{
|
|
*numOutBytes = 0;
|
|
}
|
|
else
|
|
{
|
|
if (numOut < *numOutBytes)
|
|
*numOutBytes = numOut;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CBinHex::PartFromWideBase64(LPWSTR bStr, BYTE *output, ULONG *numOutBytes)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!output) return E_INVALIDARG;
|
|
|
|
//
|
|
// Loop over the input buffer until we get numOutBytes in output
|
|
//
|
|
ULONG bCurrent = 0; // what we're in the process of filling up
|
|
int cbitFilled = 0; // how many bits in it we've filled
|
|
ULONG numOut = 0;
|
|
BYTE* pb = (BYTE*) output; // current destination (not filled)
|
|
|
|
for (WCHAR* pwch=bStr; *pwch && numOut < *numOutBytes; pwch++)
|
|
{
|
|
WCHAR wch = *pwch;
|
|
//
|
|
// Have we reached the end?
|
|
//
|
|
if (wch==L'$')
|
|
break;
|
|
//
|
|
// How much is this character worth?
|
|
//
|
|
if (wch > 255)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
BYTE bDigit = m_decodeArray[wch];
|
|
if (bDigit==BBAD)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
//
|
|
// Add in its contribution
|
|
//
|
|
bCurrent <<= 6;
|
|
bCurrent |= bDigit;
|
|
cbitFilled += 6;
|
|
//
|
|
// If we've got enough, output a byte
|
|
//
|
|
if (cbitFilled >= 8)
|
|
{
|
|
ULONG b = (bCurrent >> (cbitFilled-8)); // get's top eight valid bits
|
|
*pb++ = (BYTE)(b&0xFF); // store the byte away
|
|
cbitFilled -= 8;
|
|
numOut++;
|
|
}
|
|
} // for
|
|
|
|
_ASSERT(numOut <= *numOutBytes);
|
|
|
|
if (hr!=S_OK)
|
|
{
|
|
*numOutBytes = 0;
|
|
}
|
|
else if (numOut < *numOutBytes)
|
|
{
|
|
*numOutBytes = numOut;
|
|
}
|
|
|
|
return hr;
|
|
}
|