Leaked source code of windows server 2003
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.
 
 
 
 
 
 

264 lines
8.7 KiB

//-----------------------------------------------------------------------------
//
//
// 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);
}