|
|
//+----------------------------------------------------------------------------
// File: mime64.cxx
//
// Synopsis:
//
//-----------------------------------------------------------------------------
// Includes -------------------------------------------------------------------
#include <core.hxx>
// Constants ------------------------------------------------------------------
const LARGE_INTEGER LIB_ZERO = { 0, 0 }; const ULONG BUFFER_SIZE = 256; const UCHAR INVALID_CHAR = (UCHAR)-2; const UCHAR IGNORE_CHAR = (UCHAR)-1; const UCHAR CH_TERMINATION = '='; const char achAlpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/";
// Globals --------------------------------------------------------------------
UCHAR g_anBinary[256];
// Prototypes -----------------------------------------------------------------
inline ULONG BinaryFromASCII(UCHAR ch) { return g_anBinary[ch]; }
//+----------------------------------------------------------------------------
// Function: ProcessAttachMIME64
//
// Synopsis:
//
//-----------------------------------------------------------------------------
HRESULT ProcessAttachMIME64() { UCHAR ubin; UCHAR ch; int i;
// BUGBUG: Hard code this table
for (i=0; i < ARRAY_SIZE(g_anBinary); i++) { ch = (UCHAR)i;
switch (ch) { case ' ' : case '\t': case '\n': case '\r': ubin = IGNORE_CHAR; break;
default: if ((ch >= 'A') && (ch <= 'Z')) ubin = (UCHAR)(ch - 'A'); else if ((ch >= 'a') && (ch <= 'z')) ubin = (UCHAR)(26 + (ch - 'a')); else if ((ch >= '0') && (ch <= '9')) ubin = (UCHAR)(52 + (ch - '0')); else ubin = INVALID_CHAR; break;
case '+': ubin = 62; break;
case '/': ubin = 63; break; }
g_anBinary[i] = ubin; } return S_OK; }
//+----------------------------------------------------------------------------
// Function: EncodeMIME64
//
// Synopsis:
//
//-----------------------------------------------------------------------------
HRESULT EncodeMIME64( BYTE * pbSrc, UINT cbSrc, IStream * pstmDest, ULONG * pcbWritten) { UCHAR achOut[(2 * sizeof(UCHAR)) + CB_NEWLINE]; ULONG ichOut = 0; ULONG cbWritten; ULONG cbTotalWritten; ULONG bAccum = 0; ULONG cShift = 0; HRESULT hr = S_OK;
Assert(pbSrc); Assert(pstmDest);
if (!pcbWritten) { pcbWritten = &cbTotalWritten; }
// Convert the source string, 6-bits at a time, to ASCII characters
while (cbSrc) { bAccum <<= 8; cShift += 8; bAccum |= *pbSrc++; cbSrc--;
while (cShift >= 6) { cShift -= 6; hr = pstmDest->Write(&achAlpha[(bAccum >> cShift) & 0x3FL], 1, &cbWritten); *pcbWritten += cbWritten; if (hr) goto Cleanup; } }
// If there are bits not yet written, pad with zeros and write the resulting character
if (cShift) { bAccum <<= 6 - cShift; achOut[ichOut++] = achAlpha[(bAccum >> cShift) & 0x3FL]; }
// Add a termination character and newline
achOut[ichOut++] = CH_TERMINATION; ::memcpy(achOut+ichOut, SZ_NEWLINE, CB_NEWLINE); ichOut += CB_NEWLINE;
hr = pstmDest->Write(achOut, ichOut, &cbWritten); *pcbWritten += cbWritten; if (hr) goto Cleanup;
Cleanup: return hr; }
//+----------------------------------------------------------------------------
// Function: DecodeMIME64
//
// Synopsis:
//
//-----------------------------------------------------------------------------
HRESULT DecodeMIME64( IStream * pstmSrc, IStream * pstmDest, ULONG * pcbWritten) { UCHAR ch; UCHAR achOut[BUFFER_SIZE]; ULONG ichOut = 0; ULONG cbRead; ULONG cbWritten; ULONG cbTotalWritten = 0; ULONG bAccum = 0; ULONG cShift = 0; ULONG bValue; HRESULT hr;
if (!pcbWritten) { pcbWritten = &cbTotalWritten; }
// As long as characters remain, convert them to binary
// (This loop skips "whitespace" and stops when it encounters an out-of-range value)
for (;;) { hr = pstmSrc->Read(&ch, sizeof(ch), &cbRead); if (hr) goto Cleanup;
// Stop when no more characters remain
if (!cbRead) break;
bValue = BinaryFromASCII(ch);
// Convert known characters back to binary
if (bValue < 64) { bAccum <<= 6; cShift += 6; bAccum |= bValue;
if (cShift >= 8) { cShift -= 8; achOut[ichOut++] = (UCHAR)((bAccum >> cShift) & 0xFF);
if (ichOut >= ARRAY_SIZE(achOut)) { hr = pstmDest->Write(achOut, ichOut, &cbWritten); *pcbWritten += cbWritten; if (hr) goto Cleanup; ichOut = 0; } } }
// Skip "whitespace"
else if (bValue == IGNORE_CHAR) ;
// Stop if anything else is encountered
else break; }
// If characters remain to be written, write them now
if (ichOut) { hr = pstmDest->Write(achOut, ichOut, &cbWritten); *pcbWritten += cbWritten; if (hr) goto Cleanup; }
Cleanup: return hr; }
|