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