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.
 
 
 
 
 
 

595 lines
12 KiB

#include "stdafx.h"
#include "imgutil.h"
#include "cmimeid.h"
static CRITICAL_SECTION g_csMIMEIdentifier;
static CMIMEIdentifier* g_pMIMEIdentifier = NULL;
void InitMIMEIdentifier()
{
InitializeCriticalSection( &g_csMIMEIdentifier );
}
void CleanupMIMEIdentifier()
{
DeleteCriticalSection(&g_csMIMEIdentifier);
}
STDAPI GetMaxMIMEIDBytes( ULONG* pnMaxBytes )
{
HRESULT hResult;
if( pnMaxBytes != NULL )
{
*pnMaxBytes = 0;
}
if( pnMaxBytes == NULL )
{
return( E_POINTER );
}
EnterCriticalSection( &g_csMIMEIdentifier );
if( g_pMIMEIdentifier == NULL )
{
g_pMIMEIdentifier = new CMIMEIdentifier;
hResult = g_pMIMEIdentifier->InitFromRegistry();
if( FAILED( hResult ) )
{
delete g_pMIMEIdentifier;
g_pMIMEIdentifier = NULL;
LeaveCriticalSection( &g_csMIMEIdentifier );
return( hResult );
}
}
*pnMaxBytes = g_pMIMEIdentifier->GetMaxBytes();
LeaveCriticalSection( &g_csMIMEIdentifier );
return( S_OK );
}
STDAPI IdentifyMIMEType( const BYTE* pbBytes, ULONG nBytes,
UINT* pnFormat )
{
HRESULT hResult;
if( pnFormat != NULL )
{
*pnFormat = 0;
}
if( pbBytes == NULL )
{
return( E_INVALIDARG );
}
if( pnFormat == NULL )
{
return( E_POINTER );
}
EnterCriticalSection( &g_csMIMEIdentifier );
if( g_pMIMEIdentifier == NULL )
{
g_pMIMEIdentifier = new CMIMEIdentifier;
hResult = g_pMIMEIdentifier->InitFromRegistry();
if( FAILED( hResult ) )
{
delete g_pMIMEIdentifier;
g_pMIMEIdentifier = NULL;
LeaveCriticalSection( &g_csMIMEIdentifier );
return( hResult );
}
}
hResult = g_pMIMEIdentifier->Identify( pbBytes, nBytes, pnFormat );
LeaveCriticalSection( &g_csMIMEIdentifier );
return( hResult );
}
STDAPI SniffStream( IStream* pInStream, UINT* pnFormat,
IStream** ppOutStream )
{
HRESULT hResult;
HRESULT hIDResult;
CComPtr< ISniffStream > pSniffStream;
if( pnFormat != NULL )
{
*pnFormat = 0;
}
if( ppOutStream != NULL )
{
*ppOutStream = NULL;
}
if( pInStream == NULL )
{
return( E_INVALIDARG );
}
if( pnFormat == NULL )
{
return( E_POINTER );
}
if( ppOutStream == NULL )
{
return( E_POINTER );
}
hResult = pInStream->QueryInterface( IID_ISniffStream,
(void**)&pSniffStream );
if( FAILED( hResult ) && (hResult != E_NOINTERFACE) )
{
return( hResult );
}
if( hResult == E_NOINTERFACE )
{
hResult = CoCreateInstance( CLSID_CoSniffStream, NULL,
CLSCTX_INPROC_SERVER, IID_ISniffStream, (void**)&pSniffStream );
if( FAILED( hResult ) )
{
return( hResult );
}
hResult = pSniffStream->Init( pInStream );
if( FAILED( hResult ) )
{
return( hResult );
}
}
EnterCriticalSection( &g_csMIMEIdentifier );
if( g_pMIMEIdentifier == NULL )
{
g_pMIMEIdentifier = new CMIMEIdentifier;
hResult = g_pMIMEIdentifier->InitFromRegistry();
if( FAILED( hResult ) )
{
delete g_pMIMEIdentifier;
g_pMIMEIdentifier = NULL;
LeaveCriticalSection( &g_csMIMEIdentifier );
return( hResult );
}
}
hIDResult = g_pMIMEIdentifier->IdentifyStream( pSniffStream, pnFormat );
LeaveCriticalSection( &g_csMIMEIdentifier );
if( FAILED( hIDResult ) )
{
return( hIDResult );
}
hResult = pSniffStream->QueryInterface( IID_IStream, (void**)ppOutStream );
if( FAILED( hResult ) )
{
return( hResult );
}
return( hIDResult );
}
const LPCTSTR MIME_DATABASE_ROOT = _T( "MIME\\Database\\Content Type" );
CMIMEBitMatcher::CMIMEBitMatcher() :
m_pNext( NULL ),
m_nOffset( 0 ),
m_nBytes( 0 ),
m_pMask( NULL ),
m_pData( NULL )
{
memcpy( m_achSignature, "NoLK", 4 );
}
CMIMEBitMatcher::~CMIMEBitMatcher()
{
delete m_pMask;
delete m_pData;
}
HRESULT CMIMEBitMatcher::InitFromBinary( const BYTE* pData, ULONG nBytes,
ULONG* pnBytesToMatch )
{
const BYTE* pTrav;
#ifdef BIG_ENDIAN
BYTE pTravBig[4];
#endif
_ASSERTE( pData != NULL );
_ASSERTE( pnBytesToMatch != NULL );
if( nBytes <= sizeof( ULONG ) )
{
return( E_FAIL );
}
pTrav = pData;
#ifdef BIG_ENDIAN
pTravBig[0] = pTrav[3];
pTravBig[1] = pTrav[2];
pTravBig[2] = pTrav[1];
pTravBig[3] = pTrav[0];
m_nBytes = *(ULONG*)pTravBig;
#else
m_nBytes = *(const ULONG*)(pTrav);
#endif
pTrav += sizeof( ULONG );
if( nBytes != (2*m_nBytes)+sizeof( ULONG ) )
{
return( E_FAIL );
}
m_pMask = new BYTE[m_nBytes];
if( m_pMask == NULL )
{
return( E_OUTOFMEMORY );
}
m_pData = new BYTE[m_nBytes];
if( m_pData == NULL )
{
return( E_OUTOFMEMORY );
}
memcpy( m_pMask, pTrav, m_nBytes );
pTrav += m_nBytes;
memcpy( m_pData, pTrav, m_nBytes );
*pnBytesToMatch = m_nBytes;
return( S_OK );
}
HRESULT CMIMEBitMatcher::Match( const BYTE* pBytes, ULONG nBytes ) const
{
ULONG iByte;
ULONG nBytesToMatch;
_ASSERTE( m_nBytes > 0 );
nBytesToMatch = min( nBytes, m_nBytes );
for( iByte = 0; iByte < nBytesToMatch; iByte++ )
{
if( (pBytes[iByte]&m_pMask[iByte]) != m_pData[iByte] )
{
// The bits definitely don't match
return( S_FALSE );
}
}
if( nBytes < m_nBytes )
{
// We could have a match, but we need more data to be sure.
return( E_PENDING );
}
// We have a match
return( S_OK );
}
CMIMEType::CMIMEType() :
m_pNext( NULL ),
m_nClipboardFormat( 0 ),
m_lpBitMatchers( NULL ),
m_nMaxBytes( 0 )
{
memcpy( m_achSignature, "NoLK", 4 );
}
CMIMEType::~CMIMEType()
{
CMIMEBitMatcher* pBitMatcher;
while( m_lpBitMatchers != NULL )
{
pBitMatcher = m_lpBitMatchers;
m_lpBitMatchers = m_lpBitMatchers->m_pNext;
delete pBitMatcher;
}
}
UINT CMIMEType::GetClipboardFormat() const
{
return( m_nClipboardFormat );
}
HRESULT CMIMEType::InitFromKey( HKEY hKey, LPCTSTR pszName, ULONG* pnMaxBytes )
{
LONG nResult;
HRESULT hResult;
HKEY hBitsKey;
DWORD dwValueType;
BYTE* pData;
ULONG nBytes = 0;
ULONG nBytesToMatch;
CMIMEBitMatcher* pBitMatcher;
_ASSERTE( hKey != NULL );
_ASSERTE( pszName != NULL );
_ASSERTE( pnMaxBytes != NULL );
nResult = RegOpenKeyEx( hKey, _T( "Bits" ), 0, KEY_READ, &hBitsKey );
if( nResult != ERROR_SUCCESS )
{
return( E_FAIL );
}
nResult = RegQueryValueEx( hBitsKey, _T( "0" ), NULL, &dwValueType, NULL,
&nBytes );
if( (nResult != ERROR_SUCCESS) || (dwValueType != REG_BINARY) || nBytes > 8192 )
{
RegCloseKey( hBitsKey );
return( E_FAIL );
}
pData = LPBYTE( _alloca( nBytes ) );
nResult = RegQueryValueEx( hBitsKey, _T( "0" ), NULL, &dwValueType, pData,
&nBytes );
if( nResult != ERROR_SUCCESS )
{
RegCloseKey( hBitsKey );
return( E_FAIL );
}
RegCloseKey( hBitsKey );
pBitMatcher = new CMIMEBitMatcher;
if( pBitMatcher == NULL )
{
return( E_OUTOFMEMORY );
}
hResult = pBitMatcher->InitFromBinary( pData, nBytes, &nBytesToMatch );
if( FAILED( hResult ) )
{
delete pBitMatcher;
return( hResult );
}
m_nMaxBytes = max( m_nMaxBytes, nBytesToMatch );
m_lpBitMatchers = pBitMatcher;
m_nClipboardFormat = RegisterClipboardFormat( pszName );
if( m_nClipboardFormat == 0 )
{
return( E_FAIL );
}
*pnMaxBytes = m_nMaxBytes;
return( S_OK );
}
HRESULT CMIMEType::Match( const BYTE* pBytes, ULONG nBytes ) const
{
HRESULT hResult;
HRESULT hResultSoFar;
CMIMEBitMatcher* pBitMatcher;
_ASSERTE( pBytes != NULL );
_ASSERTE( m_nClipboardFormat != 0 );
_ASSERTE( m_lpBitMatchers != NULL );
hResultSoFar = S_FALSE;
for( pBitMatcher = m_lpBitMatchers; pBitMatcher != NULL; pBitMatcher =
pBitMatcher->m_pNext )
{
hResult = pBitMatcher->Match( pBytes, nBytes );
switch( hResult )
{
case S_OK:
return( S_OK );
break;
case E_PENDING:
hResultSoFar = E_PENDING;
break;
case S_FALSE:
break;
default:
return( hResult );
break;
}
}
return( hResultSoFar );
}
CMIMEIdentifier::CMIMEIdentifier() :
m_lpTypes( NULL ),
m_nMaxBytes( 0 )
{
memcpy( m_achSignature, "NoLK", 4 );
}
CMIMEIdentifier::~CMIMEIdentifier()
{
CMIMEType* pType;
while( m_lpTypes != NULL )
{
pType = m_lpTypes;
m_lpTypes = m_lpTypes->m_pNext;
delete pType;
}
}
ULONG CMIMEIdentifier::GetMaxBytes() const
{
return( m_nMaxBytes );
}
HRESULT CMIMEIdentifier::Identify( const BYTE* pbBytes, ULONG nBytes,
UINT* pnFormat )
{
HRESULT hResultSoFar;
CMIMEType* pType;
HRESULT hResult;
if( pnFormat != NULL )
{
*pnFormat = 0;
}
if( pbBytes == NULL )
{
return( E_INVALIDARG );
}
if( pnFormat == NULL )
{
return( E_POINTER );
}
hResultSoFar = S_FALSE;
for( pType = m_lpTypes; pType != NULL; pType = pType->m_pNext )
{
hResult = pType->Match( pbBytes, nBytes );
switch( hResult )
{
case S_OK:
*pnFormat = pType->GetClipboardFormat();
return( S_OK );
break;
case E_PENDING:
hResultSoFar = E_PENDING;
break;
case S_FALSE:
break;
default:
return( hResult );
break;
}
}
return( hResultSoFar );
}
HRESULT CMIMEIdentifier::IdentifyStream( ISniffStream* pSniffStream,
UINT* pnFormat )
{
HRESULT hResult;
HRESULT hPeekResult;
BYTE* pbBytes;
ULONG nBytesRead;
UINT nFormat;
if( pnFormat != NULL )
{
*pnFormat = 0;
}
if( pSniffStream == NULL )
{
return( E_INVALIDARG );
}
if( pnFormat == NULL )
{
return( E_POINTER );
}
pbBytes = LPBYTE( _alloca( m_nMaxBytes ) );
hPeekResult = pSniffStream->Peek( pbBytes, m_nMaxBytes, &nBytesRead );
if( FAILED( hPeekResult ) && (hPeekResult != E_PENDING) )
{
return( hPeekResult );
}
hResult = Identify( pbBytes, nBytesRead, &nFormat );
if( hResult == S_OK )
{
*pnFormat = nFormat;
}
if( (hResult == E_PENDING) && (hPeekResult == S_FALSE) )
{
return( S_FALSE );
}
return( hResult );
}
HRESULT CMIMEIdentifier::InitFromRegistry()
{
LONG nResult;
HKEY hKey;
ULONG iSubkey;
HKEY hSubkey;
TCHAR szKeyName[MAX_PATH+1];
ULONG nNameLength;
FILETIME time;
BOOL bDone;
CMIMEType* pType;
HRESULT hResult;
ULONG nMaxBytes;
if( m_lpTypes != NULL )
{
return( E_FAIL );
}
nResult = RegOpenKeyEx( HKEY_CLASSES_ROOT, MIME_DATABASE_ROOT, 0, KEY_READ,
&hKey );
if( nResult != ERROR_SUCCESS )
{
return( E_FAIL );
}
iSubkey = 0;
bDone = FALSE;
while( !bDone )
{
nNameLength = sizeof( szKeyName )/sizeof( *szKeyName );
nResult = RegEnumKeyEx( hKey, iSubkey, szKeyName, &nNameLength, NULL,
NULL, NULL, &time );
if( (nResult != ERROR_SUCCESS) && (nResult != ERROR_NO_MORE_ITEMS) )
{
RegCloseKey( hKey );
return( E_FAIL );
}
if( nResult == ERROR_SUCCESS )
{
nResult = RegOpenKeyEx( hKey, szKeyName, 0, KEY_READ, &hSubkey );
if( nResult != ERROR_SUCCESS )
{
RegCloseKey( hKey );
return( E_FAIL );
}
pType = new CMIMEType;
if( pType == NULL )
{
return( E_OUTOFMEMORY );
}
hResult = pType->InitFromKey( hSubkey, szKeyName, &nMaxBytes );
if( SUCCEEDED( hResult ) )
{
m_nMaxBytes = max( m_nMaxBytes, nMaxBytes );
pType->m_pNext = m_lpTypes;
m_lpTypes = pType;
}
else
{
delete pType;
}
RegCloseKey( hSubkey );
}
else
{
bDone = TRUE;
}
iSubkey++;
}
return( S_OK );
}