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

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name :
  4. mimemap.cxx
  5. Abstract:
  6. This module defines the member functions for MIME_MAP class
  7. and MIME_MAP_ENTRY class
  8. Author:
  9. Murali R. Krishnan ( MuraliK ) 10-Jan-1995
  10. Functions Exported:
  11. MIME_MAP_ENTRY::MIME_MAP_ENTRY()
  12. MIME_MAP::MIME_MAP()
  13. MIME_MAP::~MIME_MAP()
  14. MIME_MAP::CleanupThis()
  15. MIME_MAP::InitFromRegistry()
  16. MIME_MAP::LookupMimeEntryForFileExt()
  17. MIME_MAP::LookupMimeEntryForMimeType()
  18. --*/
  19. /************************************************************
  20. * Include Headers
  21. ************************************************************/
  22. # include <tchar.h>
  23. # include <tcpdllp.hxx>
  24. # include "mimemap.hxx"
  25. # include "hashtab.hxx"
  26. # include "iistypes.hxx"
  27. # include <imd.h>
  28. # include <mb.hxx>
  29. #if 1 // DBCS
  30. # include <mbstring.h>
  31. #endif
  32. //
  33. // Hard coded defaults for MimeEntries.
  34. //
  35. static const TCHAR sg_rgchDefaultFileExt[] = TEXT( "*");
  36. static const TCHAR sg_rgchDefaultMimeType[] = TEXT("application/octet-stream");
  37. static TCHAR sg_rgchDefaultMimeEntry[] =
  38. TEXT( "*,application/octet-stream");
  39. /************************************************************
  40. * Functions
  41. ************************************************************/
  42. static LPTSTR
  43. MMNextField( IN OUT LPTSTR * ppchFields);
  44. static BOOL
  45. ReadMimeMapFromMetabase( MULTISZ *pmszMimeMap );
  46. /************************************************************
  47. * MIME_MAP_ENTRY member functions
  48. ************************************************************/
  49. MIME_MAP_ENTRY::MIME_MAP_ENTRY(
  50. IN LPCTSTR pchMimeType,
  51. IN LPCTSTR pchFileExt)
  52. : m_strFileExt ( pchFileExt),
  53. m_strMimeType ( pchMimeType),
  54. HT_ELEMENT (),
  55. m_nRefs ( 1)
  56. /*++
  57. This function constructs a new MIME_MAP_ENTRY object.
  58. After initializing various fields, it also sets the m_fValid flag.
  59. The user needs to check MIME_MAP_ENTRY::IsValid() for the newly
  60. constructed object.
  61. --*/
  62. {
  63. m_fValid = ( m_strFileExt.IsValid() &&
  64. m_strMimeType.IsValid());
  65. } // MIME_MAP_ENTRY::MIME_MAP_ENTRY()
  66. # if DBG
  67. VOID
  68. MIME_MAP_ENTRY::Print( VOID) const
  69. {
  70. DBGPRINTF( ( DBG_CONTEXT,
  71. "MIME_MAP_ENTRY( %08x)\tRefs=%d\tFileExt=%s\tMimeType=%s\t",
  72. this,
  73. m_nRefs,
  74. m_strFileExt.QueryStr(),
  75. m_strMimeType.QueryStr()
  76. ));
  77. return;
  78. } // MIME_MAP_ENTRY::Print()
  79. # endif // DBG
  80. /************************************************************
  81. * MIME_MAP member functions
  82. ************************************************************/
  83. # define NUM_MIME_BUCKETS (7)
  84. MIME_MAP::MIME_MAP( VOID)
  85. /*++
  86. This function constructs a new MIME_MAP container object for
  87. containing the MIME_MAP_ENTRY objects.
  88. The MIME_MAP object is dummy constructed.
  89. It is set valid when we initialize the elements and
  90. create the MmeDefault entry.
  91. --*/
  92. : m_fValid ( FALSE),
  93. m_pMmeDefault ( NULL),
  94. m_htMimeEntries ( NUM_MIME_BUCKETS, "MimeMapper", 0)
  95. {
  96. } // MIME_MAP::MIME_MAP()
  97. VOID
  98. MIME_MAP::CleanupThis( VOID)
  99. /*++
  100. This function cleans up the MIME_MAP object, freeing all
  101. dynamically allocated space and reinitiallizing the list head.
  102. Returns:
  103. None
  104. --*/
  105. {
  106. if ( m_fValid) {
  107. // The mime entries in the hash table are cleaned when the hash
  108. // object is deleted.
  109. m_htMimeEntries.Cleanup();
  110. m_pMmeDefault = NULL;
  111. m_fValid = FALSE;
  112. }
  113. return;
  114. } // MIME_MAP::CleanupThis()
  115. static LPTSTR
  116. MMNextField( IN OUT LPTSTR * ppchFields)
  117. /*++
  118. This function separates and terminates the next field and returns a
  119. pointer to the same.
  120. Also it updates the incoming pointer to point to start of next field.
  121. The fields are assumed to be separated by commas.
  122. --*/
  123. {
  124. LPTSTR pchComma;
  125. LPTSTR pchField = NULL;
  126. DBG_ASSERT( ppchFields != NULL);
  127. //
  128. // Look for a comma in the input.
  129. // If none present, assume that rest of string
  130. // consists of the next field.
  131. //
  132. pchField = *ppchFields;
  133. if ( ( pchComma = _tcschr( *ppchFields, TEXT(','))) != NULL) {
  134. //
  135. // Terminate current field. Store current field name in pchComma and
  136. // update *ppchFields to contain the next field.
  137. //
  138. *pchComma = TEXT( '\0'); // terminate this field with a NULL.
  139. *ppchFields = pchComma + 1; // goto next field.
  140. } else {
  141. //
  142. // Assume everything till end of string is the current field.
  143. //
  144. *ppchFields = *ppchFields + _tcslen( *ppchFields) + 1;
  145. }
  146. pchField = ( *pchField == TEXT( '\0')) ? NULL : pchField;
  147. return ( pchField);
  148. } // MMNextField()
  149. static PMIME_MAP_ENTRY
  150. ReadAndParseMimeMapEntry( IN OUT LPTSTR * ppszValues)
  151. /*++
  152. This function parses the string containing next mime map entry and
  153. related fields and if successful creates a new MIME_MAP_ENTRY
  154. object and returns it.
  155. Otherwise it returns NULL.
  156. In either case, the incoming pointer is updated to point to next entry
  157. in the string ( past terminating NULL), assuming incoming pointer is a
  158. multi-string ( double null terminated).
  159. Arguments:
  160. ppszValues pointer to string containing the MimeEntry values.
  161. Returns:
  162. On successful MIME_ENTRY being parsed, a new MIME_MAP_ENTRY object.
  163. On error returns NULL.
  164. --*/
  165. {
  166. PMIME_MAP_ENTRY pMmeNew = NULL;
  167. DBG_ASSERT( ppszValues != NULL);
  168. LPTSTR pszMimeEntry = *ppszValues;
  169. IF_DEBUG( MIME_MAP) {
  170. DBGPRINTF( ( DBG_CONTEXT, "ReadAndParseMimeMapEntry( %s)\n",
  171. *ppszValues));
  172. }
  173. if ( pszMimeEntry != NULL && *pszMimeEntry != TEXT( '\0')) {
  174. LPTSTR pchMimeType;
  175. LPTSTR pchFileExt;
  176. pchFileExt = MMNextField( ppszValues);
  177. pchMimeType = MMNextField( ppszValues);
  178. if ( pchMimeType == NULL ||
  179. pchFileExt == NULL
  180. ) {
  181. DBGPRINTF( ( DBG_CONTEXT,
  182. " ReadAndParseMimeEntry()."
  183. " Invalid Mime String ( %s)."
  184. "MimeType( %08x): %s, FileExt( %08x): %s,",
  185. pszMimeEntry,
  186. pchMimeType, pchMimeType,
  187. pchFileExt, pchFileExt
  188. ));
  189. DBG_ASSERT( pMmeNew == NULL);
  190. } else {
  191. // Strip leading dot.
  192. if (*pchFileExt == '.')
  193. {
  194. pchFileExt++;
  195. }
  196. pMmeNew = new MIME_MAP_ENTRY( pchMimeType, pchFileExt);
  197. if ( pMmeNew != NULL && !pMmeNew->IsValid()) {
  198. //
  199. // unable to create a new MIME_MAP_ENTRY object. Delete it.
  200. //
  201. delete pMmeNew;
  202. pMmeNew = NULL;
  203. }
  204. }
  205. }
  206. return ( pMmeNew);
  207. } // ReadAndParseMimeMapEntry()
  208. DWORD
  209. MIME_MAP::InitMimeMap( VOID )
  210. /*++
  211. This function reads the mimemap stored either as a MULTI_SZ or as a sequence
  212. of REG_SZ and returns a double null terminated sequence of mime types on
  213. success. If there is any failure, the failures are ignored and it returns
  214. a NULL.
  215. Arguments:
  216. Returns:
  217. NULL on failure to open/read metabase entries
  218. non-NULL string allocated using TCP_ALLOC containing double null
  219. terminated sequence of strings with MimeMapEntries.
  220. If non-NULL the pointer should be freed using TCP_FREE by caller.
  221. --*/
  222. {
  223. DWORD dwError = NO_ERROR;
  224. DWORD dwErrorChicago = NO_ERROR;
  225. if ( IsValid()) {
  226. //
  227. // There is some mime mapping already present. Cleanup first
  228. //
  229. CleanupThis();
  230. }
  231. DBG_ASSERT( !IsValid());
  232. // First read INETSERVICES MIME database ( common types will have priority)
  233. dwError = InitFromMetabase( );
  234. if (dwError == NO_ERROR ) {
  235. m_fValid = TRUE;
  236. }
  237. // Now read Chicago shell registration database
  238. dwErrorChicago = InitFromRegistryChicagoStyle( );
  239. // If at least one succeeded - return success
  240. if (dwErrorChicago == NO_ERROR ||
  241. dwError == NO_ERROR ) {
  242. m_fValid = TRUE;
  243. return NO_ERROR;
  244. }
  245. return dwError;
  246. }
  247. static VOID
  248. GetFileExtension( IN CONST TCHAR * pchPathName,
  249. OUT LPCTSTR * ppstrExt,
  250. OUT LPCTSTR * ppstrLastSlash)
  251. {
  252. LPCTSTR pchExt = sg_rgchDefaultFileExt;
  253. DBG_ASSERT( ppstrExt != NULL && ppstrLastSlash != NULL );
  254. *ppstrLastSlash = NULL;
  255. if ( pchPathName ) {
  256. LPCTSTR pchLastDot;
  257. pchLastDot = _tcsrchr( pchPathName, TEXT( '.'));
  258. if ( pchLastDot != NULL) {
  259. LPCTSTR pchLastWhack;
  260. #if 1 // DBCS enabling for document path and file name
  261. pchLastWhack = (PCHAR)_mbsrchr( (PUCHAR)pchPathName, TEXT( '\\'));
  262. #else
  263. pchLastWhack = _tcsrchr( pchPathName, TEXT( '\\'));
  264. #endif
  265. if ( pchLastWhack == NULL) {
  266. pchLastWhack = pchPathName; // only file name specified.
  267. }
  268. if ( pchLastDot >= pchLastWhack) {
  269. // if the dot comes only in the last component, then get ext
  270. pchExt = pchLastDot + 1; // +1 to skip last dot.
  271. *ppstrLastSlash = pchLastWhack;
  272. }
  273. }
  274. }
  275. *ppstrExt = pchExt;
  276. } // GetFileExtension()
  277. DWORD
  278. MIME_MAP::LookupMimeEntryForMimeType(
  279. IN const STR & strMimeType,
  280. OUT PCMIME_MAP_ENTRY * prgMme,
  281. IN OUT LPDWORD pnMmeEntries)
  282. /*++
  283. This function maps MimeType to an array of MimeMapEntry objects that match
  284. the given MimeType.
  285. Before calling this function,
  286. ensure that you had already locked this object.
  287. After completing use of the array, unlock the MIME_MAP.
  288. The reason is:
  289. To avoid changes in the data while using the read only members of
  290. MIME_MAP.
  291. Arguments:
  292. strMimeType string containing the MimeType used in search
  293. prgpMme pointer to an array of pointers to Mme.
  294. The array is initialized to contain the
  295. read only pointers to the MIME_MAP_ENTRY objects.
  296. If prgpMme is NULL, then
  297. number of matches is counted and returned.
  298. pnMmeEntries pointer to count of entries in the array
  299. ( when called).
  300. On successful return contains total numb of entries
  301. present in the array or count of entries required.
  302. Returns:
  303. NO_ERROR on success.
  304. ERROR_INSUFFICIENT_BUFFER if the prgMme does not have enough space for
  305. copying all the read-only pointers to matched entries.
  306. other Win32 errors if any.
  307. --*/
  308. {
  309. DWORD nMaxMme = 0;
  310. DWORD iMmeFound = 0; // index into array for MmeFound
  311. HT_ITERATOR hti;
  312. HT_ELEMENT * phte;
  313. DBG_ASSERT( IsValid());
  314. if ( pnMmeEntries != NULL) {
  315. nMaxMme = *pnMmeEntries; // max that we can store.
  316. *pnMmeEntries = 0; // number found. set to default value
  317. }
  318. if ( strMimeType.IsEmpty() || nMaxMme == 0) {
  319. SetLastError( ERROR_INVALID_PARAMETER);
  320. return ( ERROR_INVALID_PARAMETER);
  321. }
  322. DWORD dwErr;
  323. dwErr = m_htMimeEntries.InitializeIterator( &hti);
  324. if ( NO_ERROR == dwErr) {
  325. DWORD iMmeFound = 0;
  326. while ( (dwErr = m_htMimeEntries.FindNextElement( &hti, &phte))
  327. == NO_ERROR) {
  328. PMIME_MAP_ENTRY pMme = (PMIME_MAP_ENTRY ) phte;
  329. DBG_ASSERT( pMme!= NULL);
  330. if ( !_tcsicmp( pMme->QueryMimeType(),
  331. strMimeType.QueryStr())) {
  332. //
  333. // We found the matching Mme. Add it to array of found.
  334. //
  335. if ( prgMme != NULL && iMmeFound < nMaxMme) {
  336. // store the pointer to found match
  337. prgMme[iMmeFound] = pMme;
  338. }
  339. iMmeFound++;
  340. } // found a match
  341. //
  342. // release the element foind before fetching the next one
  343. //
  344. phte->Dereference();
  345. } // while
  346. }
  347. DBG_REQUIRE( NO_ERROR == m_htMimeEntries.CloseIterator( &hti));
  348. dwErr = ( iMmeFound > nMaxMme) ? ERROR_INSUFFICIENT_BUFFER : NO_ERROR;
  349. *pnMmeEntries = iMmeFound;
  350. return ( dwErr);
  351. } // MIME_MAP::LookupMimeEntryForMimeType()
  352. PCMIME_MAP_ENTRY
  353. MIME_MAP::LookupMimeEntryForFileExt(
  354. IN const TCHAR * pchPathName)
  355. /*++
  356. This function mapes FileExtension to MimeEntry.
  357. The function returns a single mime entry for given file's extension.
  358. If no match is found, the default mime entry is returned.
  359. The returned entry is a readonly pointer and should not be altered.
  360. The file extension is the key field in the Hash table for mime entries.
  361. We can use the hash table lookup function to find the entry.
  362. Arguments:
  363. pchPathName pointer to string containing the path for file.
  364. ( either full path or just the file name)
  365. If NULL, then the default MimeMapEntry is returned.
  366. Returns:
  367. If a matching mime entry is found,
  368. a const pointer to MimeMapEntry object is returned.
  369. Otherwise the default mime map entry object is returned.
  370. --*/
  371. {
  372. PMIME_MAP_ENTRY pMmeMatch = m_pMmeDefault;
  373. DBG_ASSERT( IsValid());
  374. if ( pchPathName != NULL && *pchPathName ) {
  375. LPCTSTR pchExt;
  376. LPCTSTR pchLastSlash;
  377. GetFileExtension( pchPathName, &pchExt, &pchLastSlash );
  378. DBG_ASSERT( pchExt);
  379. DWORD cchExt = strlen( pchExt);
  380. for ( ;; )
  381. {
  382. //
  383. // Successfully got extension. Search in the list of MimeEntries.
  384. //
  385. pMmeMatch = (PMIME_MAP_ENTRY ) m_htMimeEntries.Lookup( pchExt, cchExt);
  386. pchExt--;
  387. if ( NULL == pMmeMatch)
  388. {
  389. pMmeMatch = m_pMmeDefault;
  390. // Look backwards for another '.' so we can support extensions
  391. // like ".xyz.xyz" or ".a.b.c".
  392. if ( pchExt > pchLastSlash )
  393. {
  394. pchExt--;
  395. while ( ( pchExt > pchLastSlash ) && ( *pchExt != '.' ) )
  396. {
  397. pchExt--;
  398. }
  399. if ( *(pchExt++) != '.' )
  400. {
  401. break;
  402. }
  403. }
  404. else
  405. {
  406. break;
  407. }
  408. }
  409. else
  410. {
  411. // mime map table is special - we do not handle ref counts
  412. // at all outside the mime-map object. Neither is there
  413. // deletion till the program ends. Just deref it here.
  414. DBG_REQUIRE( pMmeMatch->Dereference() > 0);
  415. break;
  416. }
  417. }
  418. }
  419. return ( pMmeMatch);
  420. } // MIME_MAP::LookupMimeEntryForFileExt()
  421. BOOL
  422. MIME_MAP::AddMimeMapEntry( IN PMIME_MAP_ENTRY pMmeNew)
  423. /*++
  424. This function adds the new MIME_MAP_ENTRY to the list of entries
  425. maintained in MIME_MAP
  426. Arguments:
  427. pMmeNew poitner to newly created MimeMapEntry object.
  428. Returns:
  429. Win32 error codes. NO_ERROR on success.
  430. --*/
  431. {
  432. BOOL fReturn = FALSE;
  433. if ( pMmeNew == NULL || !pMmeNew->IsValid()) {
  434. SetLastError( ERROR_INVALID_PARAMETER);
  435. DBG_ASSERT( !fReturn);
  436. } else {
  437. DBG_ASSERT( m_htMimeEntries.IsValid());
  438. fReturn = m_htMimeEntries.Insert( (HT_ELEMENT * ) pMmeNew);
  439. if ( !_tcscmp( pMmeNew->QueryFileExt(), sg_rgchDefaultFileExt)) {
  440. m_pMmeDefault = pMmeNew; // Use this as default
  441. }
  442. }
  443. return ( fReturn);
  444. } // MIME_MAP::AddMimeMapEntry()
  445. # if DBG
  446. VOID
  447. MIME_MAP::Print( VOID)
  448. {
  449. DBGPRINTF( ( DBG_CONTEXT,
  450. "MIME_MAP ( %08x). \tIsValid() = %d\n",
  451. this, IsValid())
  452. );
  453. #if 0
  454. HT_ITERATOR hti;
  455. HT_ELEMENT * phte;
  456. DWORD dwErr;
  457. dwErr = m_htMimeEntries.InitializeIterator( &hti);
  458. if ( NO_ERROR == dwErr) {
  459. while ( (dwErr = m_htMimeEntries.FindNextElement( &hti, &phte))
  460. == NO_ERROR) {
  461. DBG_ASSERT( NULL != phte);
  462. phte->Print();
  463. } // while()
  464. }
  465. DBG_REQUIRE( NO_ERROR == m_htMimeEntries.CloseIterator( &hti));
  466. # endif // 0
  467. m_htMimeEntries.Print( 1);
  468. if ( m_pMmeDefault != NULL) {
  469. DBGPRINTF( ( DBG_CONTEXT, "Default MimeMapEntry is: \n"));
  470. m_pMmeDefault->Print();
  471. } else {
  472. DBGPRINTF( ( DBG_CONTEXT, "Default MimeMapEntry is NULL\n"));
  473. }
  474. return;
  475. } // MIME_MAP::Print()
  476. # endif // DBG
  477. static BOOL
  478. ReadMimeMapFromMetabase( MULTISZ *pmszMimeMap )
  479. /*++
  480. This function reads the mimemap stored either as a MULTI_SZ or as a sequence
  481. of REG_SZ and returns a double null terminated sequence of mime types on
  482. success. If there is any failure, the failures are ignored and it returns
  483. a NULL.
  484. Arguments:
  485. pszRegKey pointer to NULL terminated string containing registry entry.
  486. Returns:
  487. NULL on failure to open/read registry entries
  488. non-NULL string allocated using TCP_ALLOC containing double null
  489. terminated sequence of strings with MimeMapEntries.
  490. If non-NULL the pointer should be freed using TCP_FREE by caller.
  491. --*/
  492. {
  493. MB mb( (IMDCOM*) IIS_SERVICE::QueryMDObject() );
  494. if ( !mb.Open( "/LM/MimeMap", METADATA_PERMISSION_READ))
  495. {
  496. //
  497. // if this fails, we're hosed.
  498. //
  499. DBGPRINTF((DBG_CONTEXT,"Open MD /LM/MimeMap returns %d\n",GetLastError() ));
  500. return FALSE;
  501. }
  502. if (!mb.GetMultisz("", MD_MIME_MAP, IIS_MD_UT_FILE, pmszMimeMap))
  503. {
  504. DBGPRINTF((DBG_CONTEXT,"Unable to read mime map from metabase: %d\n",GetLastError() ));
  505. return FALSE;
  506. }
  507. return TRUE;
  508. } // ReadMimeMapFromMetabase()
  509. DWORD
  510. MIME_MAP::InitFromMetabase( VOID )
  511. /*++
  512. This function reads the MIME_MAP entries from metabase and parses
  513. the entry, creates MIME_MAP_ENTRY object and adds the object to list
  514. of MimeMapEntries.
  515. Arguments:
  516. Returns:
  517. Win32 error code. NO_ERROR on success.
  518. Format of Storage in registry:
  519. The entries are stored in NT in tbe metabase
  520. with a list of values in following format.
  521. file-extension,i mimetype
  522. It can be stored using MULTI_SZ, but above form is convenient for both
  523. Windows 95 ( withoug MULTI_SZ) and WindowsNT.
  524. --*/
  525. {
  526. DWORD dwError = NO_ERROR;
  527. LPTSTR pszValueAlloc = NULL; // to be free using TCP_FREE()
  528. LPTSTR pszValue;
  529. MULTISZ mszMimeMap;
  530. //
  531. // There is some registry key for Mime Entries. Try open and read.
  532. //
  533. if ( !ReadMimeMapFromMetabase( &mszMimeMap ) )
  534. {
  535. mszMimeMap.Reset();
  536. if (!mszMimeMap.Append(sg_rgchDefaultMimeEntry))
  537. {
  538. return GetLastError();
  539. }
  540. }
  541. // Ignore all errors.
  542. dwError = NO_ERROR;
  543. pszValue = (LPTSTR)mszMimeMap.QueryPtr();
  544. //
  545. // Parse each MimeEntry in the string containing list of mime objects.
  546. //
  547. for( ; m_pMmeDefault == NULL; // repeat until default is set
  548. pszValue = sg_rgchDefaultMimeEntry // force default mapping in iter 2.
  549. ) {
  550. while ( *pszValue != TEXT( '\0')) {
  551. PMIME_MAP_ENTRY pMmeNew;
  552. pMmeNew = ReadAndParseMimeMapEntry( &pszValue);
  553. //
  554. // If New MimeMap entry found, Create a new object and update list
  555. //
  556. if ( (pMmeNew != NULL) &&
  557. !AddMimeMapEntry( pMmeNew)) {
  558. DBGPRINTF( ( DBG_CONTEXT,
  559. "MIME_MAP::InitFromRegistry()."
  560. " Failed to add new MIME Entry. Error = %d\n",
  561. GetLastError())
  562. );
  563. delete pMmeNew;
  564. //break;
  565. }
  566. } // while
  567. } // for
  568. return ( dwError);
  569. } // MIME_MAP::InitFromRegistryNtStyle
  570. DWORD
  571. MIME_MAP::InitFromRegistryChicagoStyle( VOID )
  572. /*++
  573. This function reads the list of MIME content-types available for regsitered file
  574. extensions. Global list of MIME objects is updated with not added yet extensions.
  575. This method should be invoked after server-specific map had been read, so it does not
  576. overwrite extensions common for two.
  577. Arguments:
  578. None.
  579. Returns:
  580. FALSE on failure to open/read registry entries
  581. TRUE on success ( does not mean any objects were added)
  582. --*/
  583. {
  584. HKEY hkeyMimeMap = NULL;
  585. HKEY hkeyMimeType = NULL;
  586. HKEY hkeyExtension = NULL;
  587. DWORD dwError = ERROR_SUCCESS;
  588. DWORD dwErrorChild = ERROR_SUCCESS;
  589. DWORD dwIndexSubKey;
  590. DWORD dwMimeSizeAllowed ;
  591. DWORD dwType;
  592. DWORD cbValue;
  593. LPTSTR pszMimeMap = NULL;
  594. TCHAR szSubKeyName[MAX_PATH];
  595. TCHAR szExtension[MAX_PATH];
  596. PTSTR pszMimeType;
  597. //
  598. // Read content types from all registered extensions
  599. //
  600. dwError = RegOpenKeyEx(HKEY_CLASSES_ROOT, // hkey
  601. "", // reg entry string
  602. 0, // dwReserved
  603. KEY_READ, // access
  604. &hkeyMimeMap); // pHkeyReturned.
  605. if ( dwError != NO_ERROR) {
  606. DBGPRINTF( ( DBG_CONTEXT,
  607. "MIME_MAP::InitFromRegistry(). Cannot open RegKey %s."
  608. "Error = %d\n",
  609. "HKCR_",
  610. dwError) );
  611. goto AddDefault;
  612. }
  613. dwIndexSubKey = 0;
  614. *szSubKeyName = '\0';
  615. pszMimeType = szSubKeyName ;
  616. dwError = RegEnumKey(hkeyMimeMap,
  617. dwIndexSubKey,
  618. szExtension,
  619. sizeof(szExtension));
  620. while (dwError == ERROR_SUCCESS ) {
  621. //
  622. // Some entries in HKEY_CLASSES_ROOT are extensions ( start with dot)
  623. // and others are file types. We don't need file types here .
  624. //
  625. if (!::IsDBCSLeadByte(*szExtension) &&
  626. TEXT('.') == *szExtension) {
  627. //
  628. // Got next eligible extension
  629. //
  630. dwErrorChild = RegOpenKeyEx( HKEY_CLASSES_ROOT, // hkey
  631. szExtension, // reg entry string
  632. 0, // dwReserved
  633. KEY_READ, // access
  634. &hkeyExtension); // pHkeyReturned.
  635. if ( dwErrorChild != NO_ERROR) {
  636. DBGPRINTF( ( DBG_CONTEXT,
  637. "MIME_MAP::InitFromRegistry(). "
  638. " Cannot open RegKey HKEY_CLASSES_ROOT\\%s."
  639. "Ignoring Error = %d\n",
  640. szExtension,
  641. dwErrorChild));
  642. break;
  643. }
  644. //
  645. // Now get content type for this extension if present
  646. //
  647. *szSubKeyName = '\0';
  648. cbValue = sizeof(szSubKeyName);
  649. dwErrorChild = RegQueryValueEx(hkeyExtension,
  650. "Content Type",
  651. NULL,
  652. &dwType,
  653. (LPBYTE)&szSubKeyName[0],
  654. &cbValue);
  655. if ( dwErrorChild == NO_ERROR) {
  656. //
  657. // Now we have MIME type and file extension
  658. // Create a new object and update list
  659. //
  660. if (!CreateAndAddMimeMapEntry(szSubKeyName,szExtension)) {
  661. dwError = GetLastError();
  662. DBGPRINTF( ( DBG_CONTEXT,
  663. "MIME_MAP::InitFromRegistry()."
  664. " Failed to add new MIME Entry. Error = %d\n",
  665. dwError)) ;
  666. }
  667. }
  668. RegCloseKey(hkeyExtension);
  669. }
  670. //
  671. // Attempt to read next extension
  672. //
  673. dwIndexSubKey++;
  674. dwError = RegEnumKey(hkeyMimeMap,
  675. dwIndexSubKey,
  676. szExtension,
  677. sizeof(szExtension));
  678. } // end_while
  679. dwError = RegCloseKey( hkeyMimeMap);
  680. AddDefault:
  681. //
  682. // Now after we are done with registry mapping - add default MIME type in case
  683. // if NT database does not exist
  684. //
  685. if (!CreateAndAddMimeMapEntry(sg_rgchDefaultMimeType,
  686. sg_rgchDefaultFileExt)) {
  687. dwError = GetLastError();
  688. DBGPRINTF( ( DBG_CONTEXT,
  689. "MIME_MAP::InitFromRegistry()."
  690. "Failed to add new MIME Entry. Error = %d\n",
  691. dwError) );
  692. }
  693. return ( NO_ERROR);
  694. } // InitFromRegistryChicagoStyle
  695. BOOL
  696. MIME_MAP::CreateAndAddMimeMapEntry(
  697. IN LPCTSTR pszMimeType,
  698. IN LPCTSTR pszExtension
  699. )
  700. {
  701. DWORD dwError;
  702. PCMIME_MAP_ENTRY pEntry = NULL;
  703. //
  704. // First check if this extension is not yet present
  705. //
  706. pEntry = LookupMimeEntryForFileExt( pszExtension );
  707. if ( pEntry )
  708. {
  709. if ( !_tcscmp( pszExtension, sg_rgchDefaultFileExt ) ||
  710. ( pEntry != m_pMmeDefault ) )
  711. {
  712. IF_DEBUG(MIME_MAP) {
  713. DBGPRINTF( ( DBG_CONTEXT,
  714. "MIME_MAP::CreateAndAddMimeEntry."
  715. " New MIME Entry already exists for extension %s .\n",
  716. pszExtension)
  717. );
  718. }
  719. return TRUE;
  720. }
  721. }
  722. //
  723. // File extensions, stored by OLE/shell registration UI have leading
  724. // dot, we need to remove it , as other code won't like it.
  725. //
  726. if (!::IsDBCSLeadByte(*pszExtension) &&
  727. TEXT('.') == *pszExtension) {
  728. pszExtension = ::CharNext(pszExtension);
  729. }
  730. PMIME_MAP_ENTRY pMmeNew;
  731. pMmeNew = new MIME_MAP_ENTRY(pszMimeType, //
  732. pszExtension //
  733. );
  734. if (!pMmeNew || !pMmeNew->IsValid()) {
  735. //
  736. // unable to create a new MIME_MAP_ENTRY object.
  737. //
  738. if (pMmeNew) {
  739. delete pMmeNew;
  740. }
  741. return FALSE;
  742. }
  743. if ( !AddMimeMapEntry( pMmeNew)) {
  744. dwError = GetLastError();
  745. DBGPRINTF( ( DBG_CONTEXT,
  746. "MIME_MAP::InitFromRegistry()."
  747. " Failed to add new MIME Entry. Error = %d\n",
  748. dwError)
  749. );
  750. delete pMmeNew;
  751. return FALSE;
  752. }
  753. return TRUE;
  754. } // MIME_MAP::CreateAndAddMimeMapEntry
  755.