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.
 
 
 
 
 
 

1044 lines
28 KiB

/*++
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