|
|
//-----------------------------------------------------------------------------
//
//
// File: b64octet.cpp
//
// Description: Implementation of Base64 encoding stream designed for use
// with UTF7 encoding.
//
// Author: Mike Swafford (MikeSwa)
//
// History:
// 10/21/98 - MikeSwa Created
//
// Copyright (C) 1998 Microsoft Corporation
//
//-----------------------------------------------------------------------------
#include "precomp.h"
//Alphabet for BASE64 encoding as defined in RFC1421 and RFC1521
CHAR g_rgchBase64[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M', 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m', 'n','o','p','q','r','s','t','u','v','w','x','y','z', '0','1','2','3','4','5','6','7','8','9','+','/' };
const DWORD BASE64_OCTET_STATE_0_BITS = 0; const DWORD BASE64_OCTET_STATE_2_BITS = 1; const DWORD BASE64_OCTET_STATE_4_BITS = 2; const DWORD BASE64_NUM_STATES = 3;
//---[ CBase64OctetStream::CBase64OctetStream ]--------------------------------
//
//
// Description:
// Default contructor for CBase64OctetStream
// Parameters:
// -
// Returns:
// -
// History:
// 10/21/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
CBase64OctetStream::CBase64OctetStream() { m_dwSignature = BASE64_OCTET_SIG; m_dwCurrentState = BASE64_OCTET_STATE_0_BITS; m_bCurrentLeftOver = 0; }
//---[ CBase64OctetStream::NextState ]------------------------------------------
//
//
// Description:
// Moves the internal state machine to the next state
// Parameters:
// -
// Returns:
// -
// History:
// 10/21/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CBase64OctetStream::NextState() { m_dwCurrentState++; if (BASE64_NUM_STATES == m_dwCurrentState) { m_dwCurrentState = BASE64_OCTET_STATE_0_BITS; m_bCurrentLeftOver = 0; } }
//---[ CBase64OctetStream::ResetState ]----------------------------------------
//
//
// Description:
// Resets the internal state machine
// Parameters:
// -
// Returns:
// -
// History:
// 10/21/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
void CBase64OctetStream::ResetState() { m_dwCurrentState = BASE64_OCTET_STATE_0_BITS; m_bCurrentLeftOver = 0; }
//---[ CBase64OctetStream::fProcessWideChar ]----------------------------------
//
//
// Description:
// Processes a single wide character and stores the results in its
// buffer. It will also ensure that there is always enough room to
// safely calll TerminateStream.
// Parameters:
// IN wch UNICODE character to process
// Returns:
// TRUE if there is enough room in the buffer to convert this char
// FALSE if there is not enough room to conver this char safely
// History:
// 10/21/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
BOOL CBase64OctetStream::fProcessWideChar(WCHAR wch) { BYTE bHigh = HIBYTE(wch); BYTE bLow = LOBYTE(wch); //At most... a single WCHAR will generate 3 base64 characters evenly or 2
//base64 characters plus a remainder which can be expanded to
//3 more characters (with trailing "==")
if (m_CharBuffer.cSpaceLeft() < 5) return FALSE;
//We know we have enough room to safely convert this character.... we
//will _VERIFY all PushChar's.
//Loop through bytes in WCHAR
_VERIFY(fProcessSingleByte(bHigh)); _VERIFY(fProcessSingleByte(bLow)); return TRUE; }
//---[ CBase64OctetStream::fProcessSingleByte ]--------------------------------
//
//
// Description:
// Does the actual work of converting a single byte to the appropriate
// base64 char(s). Also keeps track of state.
// Parameters:
// IN b BYTE to convert
// Returns:
// TRUE if there is enough room for the conversion
// FALSE otherwise
// History:
// 10/21/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
BOOL CBase64OctetStream::fProcessSingleByte(BYTE b) { const BYTE BASE64_MASK = 0x3F; //can only use 6 bits in Base64
BOOL fRet = TRUE; if (m_CharBuffer.fIsFull()) return FALSE;
switch (m_dwCurrentState) { case BASE64_OCTET_STATE_0_BITS: //There were no bits left from previous state
m_bCurrentLeftOver = b & 0x03; //there will now be 2 bits left over
m_bCurrentLeftOver <<= 4; //shift to MSB in six bits
_VERIFY(m_CharBuffer.fPushChar(g_rgchBase64[BASE64_MASK & (b >> 2)])); NextState(); break; case BASE64_OCTET_STATE_2_BITS: //There were 2 bits left from previous state..
m_bCurrentLeftOver += (0x0F & (b >> 4)); _VERIFY(m_CharBuffer.fPushChar(g_rgchBase64[BASE64_MASK & m_bCurrentLeftOver]));
//we will leave 4 low bits over
m_bCurrentLeftOver = 0x0F & b; m_bCurrentLeftOver <<= 2; //shift to MSB is six bit grouping
NextState(); break; case BASE64_OCTET_STATE_4_BITS: //There were 4 bits left over
if (m_CharBuffer.cSpaceLeft() < 2) { //There is not enough room for both characters we would push...
//so don't process byte at all.
//Do not move to the next state... do not collection $200.
fRet = FALSE; } else { m_bCurrentLeftOver += (0x03 & (b >> 6)); _VERIFY(m_CharBuffer.fPushChar(g_rgchBase64[BASE64_MASK & m_bCurrentLeftOver])); m_bCurrentLeftOver = 0; _VERIFY(m_CharBuffer.fPushChar(g_rgchBase64[BASE64_MASK & b])); NextState(); } break; default: _ASSERT(0 && "Invalid State"); } return fRet; }
//---[ CBase64OctetStream::cTerminateStream ]----------------------------------
//
//
// Description:
// Used to signal the termination of the current stream. Resets the
// state as performs any padding necessary
// Parameters:
// IN fUTF7Encoded TRUE if the stream is UTF7 encoded (does not
// require '=' padding).
// Returns:
// TRUE if there is anything left in the buffer.
// FALSE if there are no characters left to convert
// History:
// 10/21/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
BOOL CBase64OctetStream::fTerminateStream(BOOL fUTF7Encoded) { if (BASE64_OCTET_STATE_0_BITS != m_dwCurrentState) { //There should always be space left to do this
_VERIFY(m_CharBuffer.fPushChar(g_rgchBase64[m_bCurrentLeftOver])); if (!fUTF7Encoded) { switch(m_dwCurrentState) { case BASE64_OCTET_STATE_2_BITS: //There are 2 bits in this byte we did not use... which
//means that there are 2 more base64 chars to fill 24 bits
//+ => Used bits
//- => Unused (but parsed) bits
//? => Unseed bits to fill out to 24 bits
//++++ ++-- ???? ???? ???? ????
_VERIFY(m_CharBuffer.fPushChar('=')); _VERIFY(m_CharBuffer.fPushChar('=')); break; case BASE64_OCTET_STATE_4_BITS: //In these chase there is only 1 extra base64 char needed
//++++ ++++ ++++ ---- ???? ????
_VERIFY(m_CharBuffer.fPushChar('=')); break; } } } ResetState(); return (!m_CharBuffer.fIsEmpty()); }
//---[ CBase64OctetStream::fNextValidChar ]------------------------------------
//
//
// Description:
// Iterates over buffered converted characters
// Parameters:
// OUT pch Next buffer char
// Returns:
// TRUE If there is a character to get
// FALSE If there were no characters to get
// History:
// 10/21/98 - MikeSwa Created
//
//-----------------------------------------------------------------------------
BOOL CBase64OctetStream::fNextValidChar(CHAR *pch) { _ASSERT(pch); return m_CharBuffer.fPopChar(pch); }
|