1045 lines
27 KiB
C++
1045 lines
27 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name :
|
|||
|
|
|||
|
mimemap.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module defines the member functions for MIME_MAP class
|
|||
|
and MIME_MAP_ENTRY class
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Murali R. Krishnan ( MuraliK ) 10-Jan-1995
|
|||
|
|
|||
|
Functions Exported:
|
|||
|
|
|||
|
MIME_MAP_ENTRY::MIME_MAP_ENTRY()
|
|||
|
|
|||
|
MIME_MAP::MIME_MAP()
|
|||
|
MIME_MAP::~MIME_MAP()
|
|||
|
MIME_MAP::CleanupThis()
|
|||
|
MIME_MAP::InitFromRegistry()
|
|||
|
MIME_MAP::LookupMimeEntryForFileExt()
|
|||
|
MIME_MAP::LookupMimeEntryForMimeType()
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
/************************************************************
|
|||
|
* Include Headers
|
|||
|
************************************************************/
|
|||
|
|
|||
|
# include <tchar.h>
|
|||
|
# include <tcpdllp.hxx>
|
|||
|
|
|||
|
# include "mimemap.hxx"
|
|||
|
# include "hashtab.hxx"
|
|||
|
|
|||
|
# include "iistypes.hxx"
|
|||
|
# include <imd.h>
|
|||
|
# include <mb.hxx>
|
|||
|
#if 1 // DBCS
|
|||
|
# include <mbstring.h>
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Hard coded defaults for MimeEntries.
|
|||
|
//
|
|||
|
|
|||
|
static const TCHAR sg_rgchDefaultFileExt[] = TEXT( "*");
|
|||
|
|
|||
|
static const TCHAR sg_rgchDefaultMimeType[] = TEXT("application/octet-stream");
|
|||
|
static TCHAR sg_rgchDefaultMimeEntry[] =
|
|||
|
TEXT( "*,application/octet-stream");
|
|||
|
|
|||
|
/************************************************************
|
|||
|
* Functions
|
|||
|
************************************************************/
|
|||
|
|
|||
|
static LPTSTR
|
|||
|
MMNextField( IN OUT LPTSTR * ppchFields);
|
|||
|
|
|||
|
static BOOL
|
|||
|
ReadMimeMapFromMetabase( MULTISZ *pmszMimeMap );
|
|||
|
|
|||
|
|
|||
|
/************************************************************
|
|||
|
* MIME_MAP_ENTRY member functions
|
|||
|
************************************************************/
|
|||
|
|
|||
|
MIME_MAP_ENTRY::MIME_MAP_ENTRY(
|
|||
|
IN LPCTSTR pchMimeType,
|
|||
|
IN LPCTSTR pchFileExt)
|
|||
|
: m_strFileExt ( pchFileExt),
|
|||
|
m_strMimeType ( pchMimeType),
|
|||
|
HT_ELEMENT (),
|
|||
|
m_nRefs ( 1)
|
|||
|
/*++
|
|||
|
This function constructs a new MIME_MAP_ENTRY object.
|
|||
|
After initializing various fields, it also sets the m_fValid flag.
|
|||
|
The user needs to check MIME_MAP_ENTRY::IsValid() for the newly
|
|||
|
constructed object.
|
|||
|
--*/
|
|||
|
{
|
|||
|
m_fValid = ( m_strFileExt.IsValid() &&
|
|||
|
m_strMimeType.IsValid());
|
|||
|
|
|||
|
} // MIME_MAP_ENTRY::MIME_MAP_ENTRY()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
# if DBG
|
|||
|
|
|||
|
VOID
|
|||
|
MIME_MAP_ENTRY::Print( VOID) const
|
|||
|
{
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT,
|
|||
|
"MIME_MAP_ENTRY( %08x)\tRefs=%d\tFileExt=%s\tMimeType=%s\t",
|
|||
|
this,
|
|||
|
m_nRefs,
|
|||
|
m_strFileExt.QueryStr(),
|
|||
|
m_strMimeType.QueryStr()
|
|||
|
));
|
|||
|
|
|||
|
return;
|
|||
|
} // MIME_MAP_ENTRY::Print()
|
|||
|
|
|||
|
# endif // DBG
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/************************************************************
|
|||
|
* MIME_MAP member functions
|
|||
|
************************************************************/
|
|||
|
|
|||
|
# define NUM_MIME_BUCKETS (7)
|
|||
|
|
|||
|
MIME_MAP::MIME_MAP( VOID)
|
|||
|
/*++
|
|||
|
This function constructs a new MIME_MAP container object for
|
|||
|
containing the MIME_MAP_ENTRY objects.
|
|||
|
|
|||
|
The MIME_MAP object is dummy constructed.
|
|||
|
It is set valid when we initialize the elements and
|
|||
|
create the MmeDefault entry.
|
|||
|
--*/
|
|||
|
: m_fValid ( FALSE),
|
|||
|
m_pMmeDefault ( NULL),
|
|||
|
m_htMimeEntries ( NUM_MIME_BUCKETS, "MimeMapper", 0)
|
|||
|
{
|
|||
|
} // MIME_MAP::MIME_MAP()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
MIME_MAP::CleanupThis( VOID)
|
|||
|
/*++
|
|||
|
This function cleans up the MIME_MAP object, freeing all
|
|||
|
dynamically allocated space and reinitiallizing the list head.
|
|||
|
|
|||
|
Returns:
|
|||
|
None
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
if ( m_fValid) {
|
|||
|
|
|||
|
// The mime entries in the hash table are cleaned when the hash
|
|||
|
// object is deleted.
|
|||
|
m_htMimeEntries.Cleanup();
|
|||
|
m_pMmeDefault = NULL;
|
|||
|
m_fValid = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
} // MIME_MAP::CleanupThis()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
static LPTSTR
|
|||
|
MMNextField( IN OUT LPTSTR * ppchFields)
|
|||
|
/*++
|
|||
|
This function separates and terminates the next field and returns a
|
|||
|
pointer to the same.
|
|||
|
Also it updates the incoming pointer to point to start of next field.
|
|||
|
|
|||
|
The fields are assumed to be separated by commas.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LPTSTR pchComma;
|
|||
|
LPTSTR pchField = NULL;
|
|||
|
|
|||
|
DBG_ASSERT( ppchFields != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Look for a comma in the input.
|
|||
|
// If none present, assume that rest of string
|
|||
|
// consists of the next field.
|
|||
|
//
|
|||
|
|
|||
|
pchField = *ppchFields;
|
|||
|
|
|||
|
if ( ( pchComma = _tcschr( *ppchFields, TEXT(','))) != NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Terminate current field. Store current field name in pchComma and
|
|||
|
// update *ppchFields to contain the next field.
|
|||
|
//
|
|||
|
*pchComma = TEXT( '\0'); // terminate this field with a NULL.
|
|||
|
*ppchFields = pchComma + 1; // goto next field.
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Assume everything till end of string is the current field.
|
|||
|
//
|
|||
|
|
|||
|
*ppchFields = *ppchFields + _tcslen( *ppchFields) + 1;
|
|||
|
}
|
|||
|
|
|||
|
pchField = ( *pchField == TEXT( '\0')) ? NULL : pchField;
|
|||
|
return ( pchField);
|
|||
|
} // MMNextField()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
static PMIME_MAP_ENTRY
|
|||
|
ReadAndParseMimeMapEntry( IN OUT LPTSTR * ppszValues)
|
|||
|
/*++
|
|||
|
This function parses the string containing next mime map entry and
|
|||
|
related fields and if successful creates a new MIME_MAP_ENTRY
|
|||
|
object and returns it.
|
|||
|
Otherwise it returns NULL.
|
|||
|
In either case, the incoming pointer is updated to point to next entry
|
|||
|
in the string ( past terminating NULL), assuming incoming pointer is a
|
|||
|
multi-string ( double null terminated).
|
|||
|
|
|||
|
Arguments:
|
|||
|
ppszValues pointer to string containing the MimeEntry values.
|
|||
|
|
|||
|
Returns:
|
|||
|
On successful MIME_ENTRY being parsed, a new MIME_MAP_ENTRY object.
|
|||
|
On error returns NULL.
|
|||
|
--*/
|
|||
|
{
|
|||
|
PMIME_MAP_ENTRY pMmeNew = NULL;
|
|||
|
DBG_ASSERT( ppszValues != NULL);
|
|||
|
LPTSTR pszMimeEntry = *ppszValues;
|
|||
|
|
|||
|
|
|||
|
IF_DEBUG( MIME_MAP) {
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT, "ReadAndParseMimeMapEntry( %s)\n",
|
|||
|
*ppszValues));
|
|||
|
}
|
|||
|
|
|||
|
if ( pszMimeEntry != NULL && *pszMimeEntry != TEXT( '\0')) {
|
|||
|
|
|||
|
LPTSTR pchMimeType;
|
|||
|
LPTSTR pchFileExt;
|
|||
|
|
|||
|
pchFileExt = MMNextField( ppszValues);
|
|||
|
pchMimeType = MMNextField( ppszValues);
|
|||
|
|
|||
|
if ( pchMimeType == NULL ||
|
|||
|
pchFileExt == NULL
|
|||
|
) {
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT,
|
|||
|
" ReadAndParseMimeEntry()."
|
|||
|
" Invalid Mime String ( %s)."
|
|||
|
"MimeType( %08x): %s, FileExt( %08x): %s,",
|
|||
|
pszMimeEntry,
|
|||
|
pchMimeType, pchMimeType,
|
|||
|
pchFileExt, pchFileExt
|
|||
|
));
|
|||
|
|
|||
|
DBG_ASSERT( pMmeNew == NULL);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
|
|||
|
// Strip leading dot.
|
|||
|
|
|||
|
if (*pchFileExt == '.')
|
|||
|
{
|
|||
|
pchFileExt++;
|
|||
|
}
|
|||
|
|
|||
|
pMmeNew = new MIME_MAP_ENTRY( pchMimeType, pchFileExt);
|
|||
|
|
|||
|
if ( pMmeNew != NULL && !pMmeNew->IsValid()) {
|
|||
|
|
|||
|
//
|
|||
|
// unable to create a new MIME_MAP_ENTRY object. Delete it.
|
|||
|
//
|
|||
|
delete pMmeNew;
|
|||
|
pMmeNew = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ( pMmeNew);
|
|||
|
} // ReadAndParseMimeMapEntry()
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MIME_MAP::InitMimeMap( VOID )
|
|||
|
/*++
|
|||
|
This function reads the mimemap stored either as a MULTI_SZ or as a sequence
|
|||
|
of REG_SZ and returns a double null terminated sequence of mime types on
|
|||
|
success. If there is any failure, the failures are ignored and it returns
|
|||
|
a NULL.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Returns:
|
|||
|
NULL on failure to open/read metabase entries
|
|||
|
non-NULL string allocated using TCP_ALLOC containing double null
|
|||
|
terminated sequence of strings with MimeMapEntries.
|
|||
|
If non-NULL the pointer should be freed using TCP_FREE by caller.
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD dwError = NO_ERROR;
|
|||
|
DWORD dwErrorChicago = NO_ERROR;
|
|||
|
|
|||
|
|
|||
|
if ( IsValid()) {
|
|||
|
|
|||
|
//
|
|||
|
// There is some mime mapping already present. Cleanup first
|
|||
|
//
|
|||
|
|
|||
|
CleanupThis();
|
|||
|
}
|
|||
|
|
|||
|
DBG_ASSERT( !IsValid());
|
|||
|
|
|||
|
// First read INETSERVICES MIME database ( common types will have priority)
|
|||
|
dwError = InitFromMetabase( );
|
|||
|
|
|||
|
if (dwError == NO_ERROR ) {
|
|||
|
m_fValid = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
// Now read Chicago shell registration database
|
|||
|
dwErrorChicago = InitFromRegistryChicagoStyle( );
|
|||
|
|
|||
|
// If at least one succeeded - return success
|
|||
|
if (dwErrorChicago == NO_ERROR ||
|
|||
|
dwError == NO_ERROR ) {
|
|||
|
m_fValid = TRUE;
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
return dwError;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static VOID
|
|||
|
GetFileExtension( IN CONST TCHAR * pchPathName,
|
|||
|
OUT LPCTSTR * ppstrExt,
|
|||
|
OUT LPCTSTR * ppstrLastSlash)
|
|||
|
{
|
|||
|
LPCTSTR pchExt = sg_rgchDefaultFileExt;
|
|||
|
|
|||
|
DBG_ASSERT( ppstrExt != NULL && ppstrLastSlash != NULL );
|
|||
|
|
|||
|
*ppstrLastSlash = NULL;
|
|||
|
|
|||
|
if ( pchPathName ) {
|
|||
|
|
|||
|
LPCTSTR pchLastDot;
|
|||
|
|
|||
|
pchLastDot = _tcsrchr( pchPathName, TEXT( '.'));
|
|||
|
|
|||
|
if ( pchLastDot != NULL) {
|
|||
|
|
|||
|
LPCTSTR pchLastWhack;
|
|||
|
|
|||
|
#if 1 // DBCS enabling for document path and file name
|
|||
|
pchLastWhack = (PCHAR)_mbsrchr( (PUCHAR)pchPathName, TEXT( '\\'));
|
|||
|
#else
|
|||
|
pchLastWhack = _tcsrchr( pchPathName, TEXT( '\\'));
|
|||
|
#endif
|
|||
|
|
|||
|
if ( pchLastWhack == NULL) {
|
|||
|
|
|||
|
pchLastWhack = pchPathName; // only file name specified.
|
|||
|
}
|
|||
|
|
|||
|
if ( pchLastDot >= pchLastWhack) {
|
|||
|
// if the dot comes only in the last component, then get ext
|
|||
|
pchExt = pchLastDot + 1; // +1 to skip last dot.
|
|||
|
*ppstrLastSlash = pchLastWhack;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
*ppstrExt = pchExt;
|
|||
|
} // GetFileExtension()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MIME_MAP::LookupMimeEntryForMimeType(
|
|||
|
IN const STR & strMimeType,
|
|||
|
OUT PCMIME_MAP_ENTRY * prgMme,
|
|||
|
IN OUT LPDWORD pnMmeEntries)
|
|||
|
/*++
|
|||
|
This function maps MimeType to an array of MimeMapEntry objects that match
|
|||
|
the given MimeType.
|
|||
|
|
|||
|
Before calling this function,
|
|||
|
ensure that you had already locked this object.
|
|||
|
After completing use of the array, unlock the MIME_MAP.
|
|||
|
The reason is:
|
|||
|
To avoid changes in the data while using the read only members of
|
|||
|
MIME_MAP.
|
|||
|
|
|||
|
Arguments:
|
|||
|
strMimeType string containing the MimeType used in search
|
|||
|
prgpMme pointer to an array of pointers to Mme.
|
|||
|
The array is initialized to contain the
|
|||
|
read only pointers to the MIME_MAP_ENTRY objects.
|
|||
|
If prgpMme is NULL, then
|
|||
|
number of matches is counted and returned.
|
|||
|
pnMmeEntries pointer to count of entries in the array
|
|||
|
( when called).
|
|||
|
On successful return contains total numb of entries
|
|||
|
present in the array or count of entries required.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
NO_ERROR on success.
|
|||
|
ERROR_INSUFFICIENT_BUFFER if the prgMme does not have enough space for
|
|||
|
copying all the read-only pointers to matched entries.
|
|||
|
other Win32 errors if any.
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD nMaxMme = 0;
|
|||
|
DWORD iMmeFound = 0; // index into array for MmeFound
|
|||
|
HT_ITERATOR hti;
|
|||
|
HT_ELEMENT * phte;
|
|||
|
|
|||
|
DBG_ASSERT( IsValid());
|
|||
|
|
|||
|
if ( pnMmeEntries != NULL) {
|
|||
|
|
|||
|
nMaxMme = *pnMmeEntries; // max that we can store.
|
|||
|
*pnMmeEntries = 0; // number found. set to default value
|
|||
|
}
|
|||
|
|
|||
|
if ( strMimeType.IsEmpty() || nMaxMme == 0) {
|
|||
|
|
|||
|
SetLastError( ERROR_INVALID_PARAMETER);
|
|||
|
return ( ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
DWORD dwErr;
|
|||
|
dwErr = m_htMimeEntries.InitializeIterator( &hti);
|
|||
|
|
|||
|
if ( NO_ERROR == dwErr) {
|
|||
|
DWORD iMmeFound = 0;
|
|||
|
|
|||
|
while ( (dwErr = m_htMimeEntries.FindNextElement( &hti, &phte))
|
|||
|
== NO_ERROR) {
|
|||
|
|
|||
|
|
|||
|
PMIME_MAP_ENTRY pMme = (PMIME_MAP_ENTRY ) phte;
|
|||
|
DBG_ASSERT( pMme!= NULL);
|
|||
|
|
|||
|
if ( !_tcsicmp( pMme->QueryMimeType(),
|
|||
|
strMimeType.QueryStr())) {
|
|||
|
|
|||
|
//
|
|||
|
// We found the matching Mme. Add it to array of found.
|
|||
|
//
|
|||
|
|
|||
|
if ( prgMme != NULL && iMmeFound < nMaxMme) {
|
|||
|
|
|||
|
// store the pointer to found match
|
|||
|
|
|||
|
prgMme[iMmeFound] = pMme;
|
|||
|
}
|
|||
|
|
|||
|
iMmeFound++;
|
|||
|
} // found a match
|
|||
|
|
|||
|
//
|
|||
|
// release the element foind before fetching the next one
|
|||
|
//
|
|||
|
phte->Dereference();
|
|||
|
} // while
|
|||
|
}
|
|||
|
|
|||
|
DBG_REQUIRE( NO_ERROR == m_htMimeEntries.CloseIterator( &hti));
|
|||
|
|
|||
|
dwErr = ( iMmeFound > nMaxMme) ? ERROR_INSUFFICIENT_BUFFER : NO_ERROR;
|
|||
|
|
|||
|
*pnMmeEntries = iMmeFound;
|
|||
|
|
|||
|
return ( dwErr);
|
|||
|
} // MIME_MAP::LookupMimeEntryForMimeType()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PCMIME_MAP_ENTRY
|
|||
|
MIME_MAP::LookupMimeEntryForFileExt(
|
|||
|
IN const TCHAR * pchPathName)
|
|||
|
/*++
|
|||
|
This function mapes FileExtension to MimeEntry.
|
|||
|
The function returns a single mime entry for given file's extension.
|
|||
|
If no match is found, the default mime entry is returned.
|
|||
|
The returned entry is a readonly pointer and should not be altered.
|
|||
|
|
|||
|
The file extension is the key field in the Hash table for mime entries.
|
|||
|
We can use the hash table lookup function to find the entry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
pchPathName pointer to string containing the path for file.
|
|||
|
( either full path or just the file name)
|
|||
|
If NULL, then the default MimeMapEntry is returned.
|
|||
|
|
|||
|
Returns:
|
|||
|
If a matching mime entry is found,
|
|||
|
a const pointer to MimeMapEntry object is returned.
|
|||
|
Otherwise the default mime map entry object is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PMIME_MAP_ENTRY pMmeMatch = m_pMmeDefault;
|
|||
|
|
|||
|
DBG_ASSERT( IsValid());
|
|||
|
|
|||
|
if ( pchPathName != NULL && *pchPathName ) {
|
|||
|
|
|||
|
LPCTSTR pchExt;
|
|||
|
LPCTSTR pchLastSlash;
|
|||
|
|
|||
|
GetFileExtension( pchPathName, &pchExt, &pchLastSlash );
|
|||
|
DBG_ASSERT( pchExt);
|
|||
|
DWORD cchExt = strlen( pchExt);
|
|||
|
|
|||
|
for ( ;; )
|
|||
|
{
|
|||
|
//
|
|||
|
// Successfully got extension. Search in the list of MimeEntries.
|
|||
|
//
|
|||
|
|
|||
|
pMmeMatch = (PMIME_MAP_ENTRY ) m_htMimeEntries.Lookup( pchExt, cchExt);
|
|||
|
|
|||
|
pchExt--;
|
|||
|
|
|||
|
if ( NULL == pMmeMatch)
|
|||
|
{
|
|||
|
pMmeMatch = m_pMmeDefault;
|
|||
|
|
|||
|
// Look backwards for another '.' so we can support extensions
|
|||
|
// like ".xyz.xyz" or ".a.b.c".
|
|||
|
|
|||
|
if ( pchExt > pchLastSlash )
|
|||
|
{
|
|||
|
pchExt--;
|
|||
|
while ( ( pchExt > pchLastSlash ) && ( *pchExt != '.' ) )
|
|||
|
{
|
|||
|
pchExt--;
|
|||
|
}
|
|||
|
|
|||
|
if ( *(pchExt++) != '.' )
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// mime map table is special - we do not handle ref counts
|
|||
|
// at all outside the mime-map object. Neither is there
|
|||
|
// deletion till the program ends. Just deref it here.
|
|||
|
|
|||
|
DBG_REQUIRE( pMmeMatch->Dereference() > 0);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ( pMmeMatch);
|
|||
|
} // MIME_MAP::LookupMimeEntryForFileExt()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
MIME_MAP::AddMimeMapEntry( IN PMIME_MAP_ENTRY pMmeNew)
|
|||
|
/*++
|
|||
|
|
|||
|
This function adds the new MIME_MAP_ENTRY to the list of entries
|
|||
|
maintained in MIME_MAP
|
|||
|
|
|||
|
Arguments:
|
|||
|
pMmeNew poitner to newly created MimeMapEntry object.
|
|||
|
|
|||
|
Returns:
|
|||
|
Win32 error codes. NO_ERROR on success.
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOL fReturn = FALSE;
|
|||
|
|
|||
|
if ( pMmeNew == NULL || !pMmeNew->IsValid()) {
|
|||
|
|
|||
|
SetLastError( ERROR_INVALID_PARAMETER);
|
|||
|
DBG_ASSERT( !fReturn);
|
|||
|
} else {
|
|||
|
|
|||
|
DBG_ASSERT( m_htMimeEntries.IsValid());
|
|||
|
|
|||
|
fReturn = m_htMimeEntries.Insert( (HT_ELEMENT * ) pMmeNew);
|
|||
|
|
|||
|
if ( !_tcscmp( pMmeNew->QueryFileExt(), sg_rgchDefaultFileExt)) {
|
|||
|
|
|||
|
m_pMmeDefault = pMmeNew; // Use this as default
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ( fReturn);
|
|||
|
} // MIME_MAP::AddMimeMapEntry()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
# if DBG
|
|||
|
|
|||
|
VOID
|
|||
|
MIME_MAP::Print( VOID)
|
|||
|
{
|
|||
|
DBGPRINTF( ( DBG_CONTEXT,
|
|||
|
"MIME_MAP ( %08x). \tIsValid() = %d\n",
|
|||
|
this, IsValid())
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
#if 0
|
|||
|
HT_ITERATOR hti;
|
|||
|
HT_ELEMENT * phte;
|
|||
|
|
|||
|
DWORD dwErr;
|
|||
|
|
|||
|
dwErr = m_htMimeEntries.InitializeIterator( &hti);
|
|||
|
|
|||
|
if ( NO_ERROR == dwErr) {
|
|||
|
|
|||
|
while ( (dwErr = m_htMimeEntries.FindNextElement( &hti, &phte))
|
|||
|
== NO_ERROR) {
|
|||
|
|
|||
|
DBG_ASSERT( NULL != phte);
|
|||
|
phte->Print();
|
|||
|
} // while()
|
|||
|
}
|
|||
|
|
|||
|
DBG_REQUIRE( NO_ERROR == m_htMimeEntries.CloseIterator( &hti));
|
|||
|
# endif // 0
|
|||
|
|
|||
|
m_htMimeEntries.Print( 1);
|
|||
|
|
|||
|
if ( m_pMmeDefault != NULL) {
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT, "Default MimeMapEntry is: \n"));
|
|||
|
m_pMmeDefault->Print();
|
|||
|
} else {
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT, "Default MimeMapEntry is NULL\n"));
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // MIME_MAP::Print()
|
|||
|
|
|||
|
|
|||
|
# endif // DBG
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
static BOOL
|
|||
|
ReadMimeMapFromMetabase( MULTISZ *pmszMimeMap )
|
|||
|
/*++
|
|||
|
This function reads the mimemap stored either as a MULTI_SZ or as a sequence
|
|||
|
of REG_SZ and returns a double null terminated sequence of mime types on
|
|||
|
success. If there is any failure, the failures are ignored and it returns
|
|||
|
a NULL.
|
|||
|
|
|||
|
Arguments:
|
|||
|
pszRegKey pointer to NULL terminated string containing registry entry.
|
|||
|
|
|||
|
Returns:
|
|||
|
NULL on failure to open/read registry entries
|
|||
|
non-NULL string allocated using TCP_ALLOC containing double null
|
|||
|
terminated sequence of strings with MimeMapEntries.
|
|||
|
If non-NULL the pointer should be freed using TCP_FREE by caller.
|
|||
|
--*/
|
|||
|
{
|
|||
|
MB mb( (IMDCOM*) IIS_SERVICE::QueryMDObject() );
|
|||
|
|
|||
|
if ( !mb.Open( "/LM/MimeMap", METADATA_PERMISSION_READ))
|
|||
|
{
|
|||
|
//
|
|||
|
// if this fails, we're hosed.
|
|||
|
//
|
|||
|
|
|||
|
DBGPRINTF((DBG_CONTEXT,"Open MD /LM/MimeMap returns %d\n",GetLastError() ));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (!mb.GetMultisz("", MD_MIME_MAP, IIS_MD_UT_FILE, pmszMimeMap))
|
|||
|
{
|
|||
|
DBGPRINTF((DBG_CONTEXT,"Unable to read mime map from metabase: %d\n",GetLastError() ));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} // ReadMimeMapFromMetabase()
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MIME_MAP::InitFromMetabase( VOID )
|
|||
|
/*++
|
|||
|
This function reads the MIME_MAP entries from metabase and parses
|
|||
|
the entry, creates MIME_MAP_ENTRY object and adds the object to list
|
|||
|
of MimeMapEntries.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Returns:
|
|||
|
Win32 error code. NO_ERROR on success.
|
|||
|
|
|||
|
Format of Storage in registry:
|
|||
|
The entries are stored in NT in tbe metabase
|
|||
|
with a list of values in following format.
|
|||
|
file-extension,i mimetype
|
|||
|
It can be stored using MULTI_SZ, but above form is convenient for both
|
|||
|
Windows 95 ( withoug MULTI_SZ) and WindowsNT.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD dwError = NO_ERROR;
|
|||
|
|
|||
|
|
|||
|
LPTSTR pszValueAlloc = NULL; // to be free using TCP_FREE()
|
|||
|
LPTSTR pszValue;
|
|||
|
MULTISZ mszMimeMap;
|
|||
|
|
|||
|
//
|
|||
|
// There is some registry key for Mime Entries. Try open and read.
|
|||
|
//
|
|||
|
|
|||
|
if ( !ReadMimeMapFromMetabase( &mszMimeMap ) )
|
|||
|
{
|
|||
|
mszMimeMap.Reset();
|
|||
|
|
|||
|
if (!mszMimeMap.Append(sg_rgchDefaultMimeEntry))
|
|||
|
{
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Ignore all errors.
|
|||
|
dwError = NO_ERROR;
|
|||
|
|
|||
|
pszValue = (LPTSTR)mszMimeMap.QueryPtr();
|
|||
|
|
|||
|
//
|
|||
|
// Parse each MimeEntry in the string containing list of mime objects.
|
|||
|
//
|
|||
|
|
|||
|
for( ; m_pMmeDefault == NULL; // repeat until default is set
|
|||
|
pszValue = sg_rgchDefaultMimeEntry // force default mapping in iter 2.
|
|||
|
) {
|
|||
|
|
|||
|
while ( *pszValue != TEXT( '\0')) {
|
|||
|
|
|||
|
PMIME_MAP_ENTRY pMmeNew;
|
|||
|
|
|||
|
pMmeNew = ReadAndParseMimeMapEntry( &pszValue);
|
|||
|
|
|||
|
//
|
|||
|
// If New MimeMap entry found, Create a new object and update list
|
|||
|
//
|
|||
|
|
|||
|
if ( (pMmeNew != NULL) &&
|
|||
|
!AddMimeMapEntry( pMmeNew)) {
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT,
|
|||
|
"MIME_MAP::InitFromRegistry()."
|
|||
|
" Failed to add new MIME Entry. Error = %d\n",
|
|||
|
GetLastError())
|
|||
|
);
|
|||
|
|
|||
|
delete pMmeNew;
|
|||
|
//break;
|
|||
|
}
|
|||
|
} // while
|
|||
|
} // for
|
|||
|
|
|||
|
|
|||
|
return ( dwError);
|
|||
|
|
|||
|
} // MIME_MAP::InitFromRegistryNtStyle
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MIME_MAP::InitFromRegistryChicagoStyle( VOID )
|
|||
|
/*++
|
|||
|
This function reads the list of MIME content-types available for regsitered file
|
|||
|
extensions. Global list of MIME objects is updated with not added yet extensions.
|
|||
|
This method should be invoked after server-specific map had been read, so it does not
|
|||
|
overwrite extensions common for two.
|
|||
|
|
|||
|
Arguments:
|
|||
|
None.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
FALSE on failure to open/read registry entries
|
|||
|
TRUE on success ( does not mean any objects were added)
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HKEY hkeyMimeMap = NULL;
|
|||
|
HKEY hkeyMimeType = NULL;
|
|||
|
HKEY hkeyExtension = NULL;
|
|||
|
|
|||
|
DWORD dwError = ERROR_SUCCESS;
|
|||
|
DWORD dwErrorChild = ERROR_SUCCESS;
|
|||
|
DWORD dwIndexSubKey;
|
|||
|
DWORD dwMimeSizeAllowed ;
|
|||
|
DWORD dwType;
|
|||
|
DWORD cbValue;
|
|||
|
|
|||
|
LPTSTR pszMimeMap = NULL;
|
|||
|
|
|||
|
TCHAR szSubKeyName[MAX_PATH];
|
|||
|
TCHAR szExtension[MAX_PATH];
|
|||
|
|
|||
|
PTSTR pszMimeType;
|
|||
|
|
|||
|
//
|
|||
|
// Read content types from all registered extensions
|
|||
|
//
|
|||
|
dwError = RegOpenKeyEx(HKEY_CLASSES_ROOT, // hkey
|
|||
|
"", // reg entry string
|
|||
|
0, // dwReserved
|
|||
|
KEY_READ, // access
|
|||
|
&hkeyMimeMap); // pHkeyReturned.
|
|||
|
|
|||
|
if ( dwError != NO_ERROR) {
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT,
|
|||
|
"MIME_MAP::InitFromRegistry(). Cannot open RegKey %s."
|
|||
|
"Error = %d\n",
|
|||
|
"HKCR_",
|
|||
|
dwError) );
|
|||
|
|
|||
|
goto AddDefault;
|
|||
|
}
|
|||
|
|
|||
|
dwIndexSubKey = 0;
|
|||
|
|
|||
|
*szSubKeyName = '\0';
|
|||
|
pszMimeType = szSubKeyName ;
|
|||
|
|
|||
|
dwError = RegEnumKey(hkeyMimeMap,
|
|||
|
dwIndexSubKey,
|
|||
|
szExtension,
|
|||
|
sizeof(szExtension));
|
|||
|
|
|||
|
while (dwError == ERROR_SUCCESS ) {
|
|||
|
|
|||
|
//
|
|||
|
// Some entries in HKEY_CLASSES_ROOT are extensions ( start with dot)
|
|||
|
// and others are file types. We don't need file types here .
|
|||
|
//
|
|||
|
if (!::IsDBCSLeadByte(*szExtension) &&
|
|||
|
TEXT('.') == *szExtension) {
|
|||
|
|
|||
|
//
|
|||
|
// Got next eligible extension
|
|||
|
//
|
|||
|
dwErrorChild = RegOpenKeyEx( HKEY_CLASSES_ROOT, // hkey
|
|||
|
szExtension, // reg entry string
|
|||
|
0, // dwReserved
|
|||
|
KEY_READ, // access
|
|||
|
&hkeyExtension); // pHkeyReturned.
|
|||
|
|
|||
|
if ( dwErrorChild != NO_ERROR) {
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT,
|
|||
|
"MIME_MAP::InitFromRegistry(). "
|
|||
|
" Cannot open RegKey HKEY_CLASSES_ROOT\\%s."
|
|||
|
"Ignoring Error = %d\n",
|
|||
|
szExtension,
|
|||
|
dwErrorChild));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now get content type for this extension if present
|
|||
|
//
|
|||
|
*szSubKeyName = '\0';
|
|||
|
cbValue = sizeof(szSubKeyName);
|
|||
|
|
|||
|
dwErrorChild = RegQueryValueEx(hkeyExtension,
|
|||
|
"Content Type",
|
|||
|
NULL,
|
|||
|
&dwType,
|
|||
|
(LPBYTE)&szSubKeyName[0],
|
|||
|
&cbValue);
|
|||
|
if ( dwErrorChild == NO_ERROR) {
|
|||
|
|
|||
|
//
|
|||
|
// Now we have MIME type and file extension
|
|||
|
// Create a new object and update list
|
|||
|
//
|
|||
|
|
|||
|
if (!CreateAndAddMimeMapEntry(szSubKeyName,szExtension)) {
|
|||
|
dwError = GetLastError();
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT,
|
|||
|
"MIME_MAP::InitFromRegistry()."
|
|||
|
" Failed to add new MIME Entry. Error = %d\n",
|
|||
|
dwError)) ;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
RegCloseKey(hkeyExtension);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to read next extension
|
|||
|
//
|
|||
|
dwIndexSubKey++;
|
|||
|
|
|||
|
dwError = RegEnumKey(hkeyMimeMap,
|
|||
|
dwIndexSubKey,
|
|||
|
szExtension,
|
|||
|
sizeof(szExtension));
|
|||
|
|
|||
|
} // end_while
|
|||
|
|
|||
|
dwError = RegCloseKey( hkeyMimeMap);
|
|||
|
|
|||
|
AddDefault:
|
|||
|
|
|||
|
//
|
|||
|
// Now after we are done with registry mapping - add default MIME type in case
|
|||
|
// if NT database does not exist
|
|||
|
//
|
|||
|
if (!CreateAndAddMimeMapEntry(sg_rgchDefaultMimeType,
|
|||
|
sg_rgchDefaultFileExt)) {
|
|||
|
|
|||
|
dwError = GetLastError();
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT,
|
|||
|
"MIME_MAP::InitFromRegistry()."
|
|||
|
"Failed to add new MIME Entry. Error = %d\n",
|
|||
|
dwError) );
|
|||
|
}
|
|||
|
|
|||
|
return ( NO_ERROR);
|
|||
|
|
|||
|
} // InitFromRegistryChicagoStyle
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
MIME_MAP::CreateAndAddMimeMapEntry(
|
|||
|
IN LPCTSTR pszMimeType,
|
|||
|
IN LPCTSTR pszExtension
|
|||
|
)
|
|||
|
{
|
|||
|
DWORD dwError;
|
|||
|
PCMIME_MAP_ENTRY pEntry = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// First check if this extension is not yet present
|
|||
|
//
|
|||
|
|
|||
|
pEntry = LookupMimeEntryForFileExt( pszExtension );
|
|||
|
if ( pEntry )
|
|||
|
{
|
|||
|
if ( !_tcscmp( pszExtension, sg_rgchDefaultFileExt ) ||
|
|||
|
( pEntry != m_pMmeDefault ) )
|
|||
|
{
|
|||
|
IF_DEBUG(MIME_MAP) {
|
|||
|
DBGPRINTF( ( DBG_CONTEXT,
|
|||
|
"MIME_MAP::CreateAndAddMimeEntry."
|
|||
|
" New MIME Entry already exists for extension %s .\n",
|
|||
|
pszExtension)
|
|||
|
);
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// File extensions, stored by OLE/shell registration UI have leading
|
|||
|
// dot, we need to remove it , as other code won't like it.
|
|||
|
//
|
|||
|
if (!::IsDBCSLeadByte(*pszExtension) &&
|
|||
|
TEXT('.') == *pszExtension) {
|
|||
|
pszExtension = ::CharNext(pszExtension);
|
|||
|
}
|
|||
|
|
|||
|
PMIME_MAP_ENTRY pMmeNew;
|
|||
|
|
|||
|
pMmeNew = new MIME_MAP_ENTRY(pszMimeType, //
|
|||
|
pszExtension //
|
|||
|
);
|
|||
|
|
|||
|
if (!pMmeNew || !pMmeNew->IsValid()) {
|
|||
|
|
|||
|
//
|
|||
|
// unable to create a new MIME_MAP_ENTRY object.
|
|||
|
//
|
|||
|
if (pMmeNew) {
|
|||
|
delete pMmeNew;
|
|||
|
}
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if ( !AddMimeMapEntry( pMmeNew)) {
|
|||
|
|
|||
|
dwError = GetLastError();
|
|||
|
|
|||
|
DBGPRINTF( ( DBG_CONTEXT,
|
|||
|
"MIME_MAP::InitFromRegistry()."
|
|||
|
" Failed to add new MIME Entry. Error = %d\n",
|
|||
|
dwError)
|
|||
|
);
|
|||
|
|
|||
|
delete pMmeNew;
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} // MIME_MAP::CreateAndAddMimeMapEntry
|
|||
|
|
|||
|
|