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.

1364 lines
41 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: datasnif.cxx
  7. //
  8. // Contents: Stream Mime type checking (attempts to guess the MIME type
  9. // of a buffer by simple pattern matching).
  10. //
  11. // Classes: CContentAnalyzer
  12. //
  13. // Functions: private:
  14. // CContentAnalyzer::SampleData
  15. // CContentAnalyzer::IsBMP
  16. // CContentAnalyzer::GetDataFormat
  17. // CContentAnalyzer::FormatAgreesWithData
  18. // CContentAnalyzer::MatchDWordAtOffset
  19. // CContentAnalyzer::FindAppFromExt
  20. // CContentAnalyzer::CheckTextHeaders
  21. // CContentAnalyzer::CheckBinaryHeaders
  22. //
  23. // public:
  24. // CContentAnalyzer::FindMimeFromData
  25. // ::FindMimeFromData
  26. //
  27. //
  28. // History: 05-25-96 AdriaanC (Adriaan Canter) Created
  29. // 07-16-96 AdriaanC (Adriaan Canter) Modified
  30. // 08-06-96 AdriaanC (Adriaan Canter) Modified
  31. // 08-14-96 AdriaanC (Adriaan Canter) Modified
  32. //
  33. //----------------------------------------------------------------------------
  34. #include <trans.h>
  35. #include "datasnif.hxx"
  36. #include <shlwapip.h>
  37. #ifdef UNIX
  38. #include <mainwin.h>
  39. #endif
  40. PerfDbgTag(tagDataSniff, "Urlmon", "Log DataSniff", DEB_DATA);
  41. // Max no. bytes to look at
  42. #define SAMPLE_SIZE 256
  43. // Registry Key for app/fileext associations
  44. #define szApplicationRegistryKey "\\Shell\\Open\\Command"
  45. #define szApplicationRegistryKey2 "\\Shell\\Connect To\\Command"
  46. #define szMimeRegistryKey "MIME\\Database\\Content Type\\"
  47. // Magic header words
  48. #define AU_SUN_MAGIC 0x2e736e64
  49. #define AU_SUN_INV_MAGIC 0x646e732e
  50. #define AU_DEC_MAGIC 0x2e736400
  51. #define AU_DEC_INV_MAGIC 0x0064732e
  52. #define AIFF_MAGIC 0x464f524d
  53. #define AIFF_INV_MAGIC 0x4d524f46
  54. #define AIFF_MAGIC_MORE_1 'AIFF'
  55. #define AIFF_MAGIC_MORE_2 'AIFC'
  56. #define RIFF_MAGIC 0x52494646
  57. #define AVI_MAGIC 0x41564920
  58. #define WAV_MAGIC 0x57415645
  59. #define JAVA_MAGIC 0xcafebabe
  60. #define MPEG_MAGIC 0x000001b3
  61. #define MPEG_MAGIC_2 0x000001ba
  62. #define EMF_MAGIC_1 0x01000000
  63. #define EMF_MAGIC_2 0x20454d46
  64. #define WMF_MAGIC 0xd7cdc69a
  65. #define JPEG_MAGIC_1 0xFF
  66. #define JPEG_MAGIC_2 0xD8
  67. // Magic header text
  68. CHAR vszRichTextMagic[] = "{\\rtf";
  69. CHAR vszPostscriptMagic[] = "%!";
  70. CHAR vszBinHexMagic[] = "onverted with BinHex";
  71. CHAR vszBase64Magic[] = "begin";
  72. CHAR vszGif87Magic[] = "GIF87";
  73. CHAR vszGif89Magic[] = "GIF89";
  74. CHAR vszTiffMagic[] = "MM";
  75. CHAR vszBmpMagic[] = "BM";
  76. CHAR vszZipMagic[] = "PK";
  77. CHAR vszExeMagic[] = "MZ";
  78. CHAR vszPngMagic[] = "\211PNG\r\n\032\n";
  79. CHAR vszCompressMagic[] = "\037\235";
  80. CHAR vszGzipMagic[] = "\037\213";
  81. CHAR vszXbmMagic1[] = "define";
  82. CHAR vszXbmMagic2[] = "width";
  83. CHAR vszXbmMagic3[] = "bits";
  84. CHAR vszPdfMagic[] = "%PDF";
  85. CHAR vszJGMagic[] = "JG";
  86. CHAR vszMIDMagic[] = "MThd";
  87. // null MIME type
  88. WCHAR vwzNULL[] = L"(null)";
  89. // 7 bit MIME Types
  90. WCHAR vwzTextPlain[] = L"text/plain";
  91. WCHAR vwzTextRichText[] = L"text/richtext";
  92. WCHAR vwzImageXBitmap[] = L"image/x-xbitmap";
  93. WCHAR vwzApplicationPostscript[] = L"application/postscript";
  94. WCHAR vwzApplicationBase64[] = L"application/base64";
  95. WCHAR vwzApplicationMacBinhex[] = L"application/macbinhex40";
  96. WCHAR vwzApplicationPdf[] = L"application/pdf";
  97. WCHAR vwzApplicationCDF[] = L"application/x-cdf";
  98. WCHAR vwzApplicationNETCDF[] = L"application/x-netcdf";
  99. WCHAR vwzmultipartmixedreplace[] = L"multipart/x-mixed-replace";
  100. WCHAR vwzmultipartmixed[] = L"multipart/mixed";
  101. WCHAR vwzTextScriptlet[] = L"text/scriptlet";
  102. WCHAR vwzTextComponent[] = L"text/x-component";
  103. WCHAR vwzTextXML[] = L"text/xml";
  104. WCHAR vwzApplicationHTA[] = L"application/hta";
  105. // 8 bit MIME types
  106. WCHAR vwzAudioAiff[] = L"audio/x-aiff";
  107. WCHAR vwzAudioBasic[] = L"audio/basic";
  108. WCHAR vwzAudioWav[] = L"audio/wav";
  109. WCHAR vwzAudioMID[] = L"audio/mid";
  110. WCHAR vwzImageGif[] = L"image/gif";
  111. WCHAR vwzImagePJpeg[] = L"image/pjpeg";
  112. WCHAR vwzImageJpeg[] = L"image/jpeg";
  113. WCHAR vwzImageTiff[] = L"image/tiff";
  114. WCHAR vwzImagePng[] = L"image/x-png";
  115. WCHAR vwzImageBmp[] = L"image/bmp";
  116. WCHAR vwzImageJG[] = L"image/x-jg";
  117. WCHAR vwzImageEmf[] = L"image/x-emf";
  118. WCHAR vwzImageWmf[] = L"image/x-wmf";
  119. WCHAR vwzVideoAvi[] = L"video/avi";
  120. WCHAR vwzVideoMpeg[] = L"video/mpeg";
  121. WCHAR vwzApplicationCompressed[] = L"application/x-compressed";
  122. WCHAR vwzApplicationZipCompressed[] = L"application/x-zip-compressed";
  123. WCHAR vwzApplicationGzipCompressed[] = L"application/x-gzip-compressed";
  124. WCHAR vwzApplicationJava[] = L"application/java";
  125. WCHAR vwzApplicationMSDownload[] = L"application/x-msdownload";
  126. // 7 or 8 bit MIME types
  127. WCHAR vwzTextHTML[] = L"text/html";
  128. WCHAR vwzApplicationOctetStream[] = L"application/octet-stream";
  129. //+---------------------------------------------------------------------------
  130. //
  131. // Method: CContentAnalyzer::SampleData
  132. //
  133. // Synopsis:
  134. //
  135. // Arguments: (void)
  136. //
  137. // Returns: (void)
  138. //
  139. // History: 5-25-96 AdriaanC (Adriaan Canter) Created
  140. //
  141. // Notes:
  142. //
  143. //----------------------------------------------------------------------------
  144. void CContentAnalyzer::SampleData()
  145. {
  146. DEBUG_ENTER((DBG_TRANS,
  147. None,
  148. "CContentAnalyzer::SampleData",
  149. "this=%#x",
  150. this
  151. ));
  152. BOOL fFoundFirstXBitMapTag = FALSE;
  153. BOOL fFoundSecondXBitMapTag = FALSE;
  154. BOOL fFoundAsciiChar = FALSE;
  155. int nHTMLConfidence = 0;
  156. unsigned char *p = (unsigned char*) _pBuf;
  157. _cbNL = _cbCR = _cbFF = _cbText = _cbCtrl = _cbHigh = 0;
  158. // Count incidence of character types.
  159. for (int i = 0; i < _cbSample - 1; i++)
  160. {
  161. fFoundAsciiChar = FALSE;
  162. if (*p == '\n') // new line
  163. {
  164. _cbNL++;
  165. }
  166. else if (*p == '\r') // carriage return
  167. {
  168. _cbCR++;
  169. }
  170. else if (*p == '\f') // form feed
  171. {
  172. _cbFF++;
  173. }
  174. else if (*p == '\t') // tab
  175. {
  176. _cbText++;
  177. }
  178. else if (*p < 32) // control character
  179. {
  180. _cbCtrl++;
  181. }
  182. else if (*p >= 32 && *p < 128) // regular text
  183. {
  184. _cbText++;
  185. fFoundAsciiChar = TRUE;
  186. }
  187. else // extended text
  188. {
  189. _cbHigh++;
  190. }
  191. if (fFoundAsciiChar)
  192. {
  193. // check for html
  194. if (*p == '<')
  195. {
  196. if (!StrCmpNIC((char*) p+1, "?XML", sizeof("?XML") - 1) &&
  197. (
  198. (*(p+5) == ':') ||
  199. (*(p+5) == ' ') ||
  200. (*(p+5) == '\t')) )
  201. {
  202. _fFoundXML = TRUE;
  203. // don't break : for CDF
  204. }
  205. if (!StrCmpNIC((char*) p+1, "SCRIPTLET", sizeof("SCRIPTLET") - 1))
  206. {
  207. _fFoundTextScriptlet = TRUE;
  208. break;
  209. }
  210. if (!StrCmpNIC((char*) p+1, "HTML", sizeof("HTML") - 1)
  211. || !StrCmpNIC((char*) p+1, "HEAD", sizeof("HEAD") - 1)
  212. || !StrCmpNIC((char*) p+1, "TITLE", sizeof("TITLE") - 1)
  213. || !StrCmpNIC((char*) p+1, "BODY", sizeof("BODY") - 1)
  214. || !StrCmpNIC((char*) p+1, "SCRIPT", sizeof("SCRIPT") - 1)
  215. || !StrCmpNIC((char*) p+1, "A HREF", sizeof("A HREF") - 1)
  216. || !StrCmpNIC((char*) p+1, "PRE", sizeof("PRE") - 1)
  217. || !StrCmpNIC((char*) p+1, "IMG", sizeof("IMG") - 1)
  218. || !StrCmpNIC((char*) p+1, "PLAINTEXT", sizeof("PLAINTEXT") - 1)
  219. || !StrCmpNIC((char*) p+1, "TABLE", sizeof("TABLE") - 1))
  220. {
  221. _fFoundHTML = TRUE;
  222. break;
  223. }
  224. else if ( !StrCmpNIC((char*) p+1, "HR", sizeof("HR") - 1)
  225. || !StrCmpNIC((char*) p+1, "A", sizeof("A") - 1)
  226. || !StrCmpNIC((char*) p+1, "/A", sizeof("/A") - 1)
  227. || !StrCmpNIC((char*) p+1, "B", sizeof("B") - 1)
  228. || !StrCmpNIC((char*) p+1, "/B", sizeof("/B") - 1)
  229. || !StrCmpNIC((char*) p+1, "P", sizeof("P") - 1)
  230. || !StrCmpNIC((char*) p+1, "/P", sizeof("/P") - 1)
  231. || !StrCmpNIC((char*) p+1, "!--", sizeof("!--") - 1)
  232. )
  233. {
  234. //
  235. // In order for this branch to identify this is HTML
  236. // We have to make sure:
  237. // 1. some HTML control char exists
  238. // 2. We've scanned the whole data block
  239. // 3. 2/3 of the data should be text
  240. //
  241. nHTMLConfidence += 50;
  242. if ( nHTMLConfidence >= 100
  243. && i == _cbSample - 1
  244. && _cbText >= ((_cbSample * 2) / 3)
  245. )
  246. {
  247. _fFoundHTML = TRUE;
  248. break;
  249. }
  250. }
  251. if (!StrCmpNIC((char*) p+1, "CHANNEL", sizeof("CHANNEL") - 1))
  252. {
  253. _fFoundCDF = TRUE;
  254. break;
  255. }
  256. }
  257. else if (!StrCmpNIC((char*) p, "-->", sizeof("-->") - 1))
  258. {
  259. // comment begin
  260. // I really want to make sure that most of the
  261. // char are printable
  262. // potential issue: International code page?
  263. nHTMLConfidence += 50;
  264. if ( (nHTMLConfidence >= 100)
  265. && (i == _cbSample - 1 )
  266. && (_cbText > (_cbSample * 2 /3) )
  267. )
  268. {
  269. _fFoundHTML = TRUE;
  270. break;
  271. }
  272. }
  273. // check for xbitmap
  274. else if (*p == '#')
  275. {
  276. if (!StrCmpNC((char*) p+1, vszXbmMagic1, sizeof(vszXbmMagic1) - 1))
  277. fFoundFirstXBitMapTag = TRUE;
  278. }
  279. else if (*p == '_' && fFoundSecondXBitMapTag)
  280. {
  281. if (!StrCmpNC((char*) p+1, vszXbmMagic3, sizeof(vszXbmMagic3) - 1))
  282. {
  283. _fFoundXBitMap = TRUE;
  284. break;
  285. }
  286. }
  287. else if (*p == '_' && fFoundFirstXBitMapTag)
  288. {
  289. if (!StrCmpNC((char*) p+1, vszXbmMagic2, sizeof(vszXbmMagic2) - 1))
  290. fFoundSecondXBitMapTag = TRUE;
  291. }
  292. // MacBinhex
  293. else if (*p == 'c')
  294. {
  295. if (!StrCmpNC((char*) p+1, vszBinHexMagic, sizeof(vszBinHexMagic) - 1))
  296. {
  297. _fFoundMacBinhex = TRUE;
  298. break;
  299. }
  300. }
  301. }
  302. p++;
  303. }
  304. DEBUG_LEAVE(0);
  305. }
  306. //+---------------------------------------------------------------------------
  307. //
  308. // Method: CContentAnalyzer::IsBMP
  309. //
  310. // Synopsis:
  311. //
  312. // Arguments: (void)
  313. //
  314. // Returns: BOOL
  315. //
  316. // History: 5-25-96 AdriaanC (Adriaan Canter) Created
  317. //
  318. // Notes:
  319. //
  320. //----------------------------------------------------------------------------
  321. BOOL CContentAnalyzer::IsBMP()
  322. {
  323. DEBUG_ENTER((DBG_TRANS,
  324. Bool,
  325. "CContentAnalyzer::IsBMP",
  326. "this=%#x",
  327. this
  328. ));
  329. BOOL bRetVal = TRUE;
  330. BITMAPFILEHEADER UNALIGNED *pBMFileHdr;
  331. if (_cbSample < 2)
  332. {
  333. bRetVal = FALSE;
  334. }
  335. // Check header
  336. if (StrCmpNC(_pBuf, vszBmpMagic, sizeof(vszBmpMagic) - 1))
  337. {
  338. bRetVal = FALSE;
  339. }
  340. // Sample size needs to be big enough.
  341. if (_cbSample < sizeof(BITMAPFILEHEADER))
  342. {
  343. bRetVal = FALSE;
  344. }
  345. pBMFileHdr = (BITMAPFILEHEADER*)(_pBuf);
  346. #ifdef UNIX
  347. /* Use 14 on Unix, because we want the size without the padding
  348. * done on Unix. sizeof(BITMAPFILEHEADER) = 16 on Unix with padding
  349. */
  350. #define UNIX_BITMAP_HEADER_SIZE 14
  351. BITMAPFILEHEADER bmFileHeader;
  352. if(MwReadBITMAPFILEHEADER((LPBYTE)_pBuf, UNIX_BITMAP_HEADER_SIZE, &bmFileHeader))
  353. pBMFileHdr = &bmFileHeader;
  354. #endif /* UNIX */
  355. // The reserved fields must be set to 0
  356. if (pBMFileHdr->bfReserved1!=0 || pBMFileHdr->bfReserved2!=0)
  357. {
  358. bRetVal = FALSE;
  359. }
  360. DEBUG_LEAVE(bRetVal);
  361. return bRetVal;
  362. }
  363. //+---------------------------------------------------------------------------
  364. //
  365. // Method: CContentAnalyzer::GetDataFormat
  366. //
  367. // Synopsis:
  368. //
  369. // Arguments: (WCHAR* wzMimeType)
  370. //
  371. // Returns: BOOL dwDataFormat
  372. //
  373. // History: 7-21-96 AdriaanC (Adriaan Canter) Created
  374. //
  375. // Notes:
  376. //
  377. //----------------------------------------------------------------------------
  378. DWORD CContentAnalyzer::GetDataFormat(LPCWSTR wzMimeType)
  379. {
  380. DEBUG_ENTER((DBG_TRANS,
  381. Dword,
  382. "CContentAnalyzer::GetDataFormat",
  383. "this=%#x, %.80wq",
  384. this, wzMimeType
  385. ));
  386. CLIPFORMAT cfFormat;
  387. DATAFORMAT dwDataFormat;
  388. HRESULT hr;
  389. if (!wzMimeType)
  390. {
  391. DEBUG_LEAVE(DATAFORMAT_AMBIGUOUS);
  392. return DATAFORMAT_AMBIGUOUS;
  393. }
  394. if( !_wcsicmp(wzMimeType, vwzNULL) )
  395. {
  396. DEBUG_LEAVE(DATAFORMAT_AMBIGUOUS);
  397. return DATAFORMAT_AMBIGUOUS;
  398. }
  399. hr = FindMediaTypeFormat(wzMimeType, &cfFormat, (DWORD *)&dwDataFormat);
  400. if (hr == S_OK)
  401. {
  402. DEBUG_LEAVE(dwDataFormat);
  403. return dwDataFormat;
  404. }
  405. else
  406. {
  407. DEBUG_LEAVE(DATAFORMAT_UNKNOWN);
  408. return DATAFORMAT_UNKNOWN;
  409. }
  410. }
  411. //+---------------------------------------------------------------------------
  412. //
  413. // Method: CContentAnalyzer::FormatAgreesWithData
  414. //
  415. // Synopsis:
  416. //
  417. // Arguments: (void)
  418. //
  419. // Returns: BOOL
  420. //
  421. // History: 8-14-96 AdriaanC (Adriaan Canter) Created
  422. //
  423. // Notes:
  424. //
  425. //----------------------------------------------------------------------------
  426. BOOL CContentAnalyzer::FormatAgreesWithData(DWORD dwFormat)
  427. {
  428. DEBUG_ENTER((DBG_TRANS,
  429. Bool,
  430. "CContentAnalyzer::FormatAgreesWithData",
  431. "this=%#x, %#x",
  432. this, dwFormat
  433. ));
  434. if (dwFormat == DATAFORMAT_TEXT && _fBinary == FALSE
  435. || dwFormat == DATAFORMAT_BINARY && _fBinary == TRUE
  436. || dwFormat == DATAFORMAT_TEXTORBINARY)
  437. {
  438. DEBUG_LEAVE(TRUE);
  439. return TRUE;
  440. }
  441. DEBUG_LEAVE(FALSE);
  442. return FALSE;
  443. }
  444. //+---------------------------------------------------------------------------
  445. //
  446. // Method: CContentAnalyzer::MatchDWordAtOffset
  447. //
  448. // Synopsis: Determines if a given magic word is found at
  449. // the specified offset.
  450. //
  451. // Arguments: (DWORD magic, int offset)
  452. //
  453. // Returns: BOOL
  454. //
  455. // History: 5-25-96 AdriaanC (Adriaan Canter) Created
  456. //
  457. // Notes:
  458. //
  459. //----------------------------------------------------------------------------
  460. BOOL CContentAnalyzer::MatchDWordAtOffset(DWORD magic, int offset)
  461. {
  462. DEBUG_ENTER((DBG_TRANS,
  463. Bool,
  464. "CContentAnalyzer::MatchDWordAtOffset",
  465. "this=%#x, %#x, %d",
  466. this, magic, offset
  467. ));
  468. BOOL bRetVal = TRUE;
  469. DWORD dwWord = 0;
  470. unsigned char* p = (unsigned char*) _pBuf;
  471. if (_cbSample < offset + (int) sizeof(DWORD))
  472. {
  473. DEBUG_LEAVE(FALSE);
  474. return FALSE;
  475. }
  476. dwWord = (p[offset] << 24)
  477. | (p[offset+1] << 16)
  478. | (p[offset+2] << 8)
  479. | p[offset+3];
  480. if (magic != dwWord)
  481. {
  482. bRetVal = FALSE;
  483. }
  484. DEBUG_LEAVE(bRetVal);
  485. return bRetVal;
  486. }
  487. //+---------------------------------------------------------------------------
  488. //
  489. // Method: CContentAnalyzer::FindAppFromExt
  490. //
  491. // Synopsis: Determines an associated application from
  492. // a given file extension
  493. //
  494. // Arguments: (LPSTR pszExt, LPSTR pszCommand (command line))
  495. //
  496. // Returns: BOOL (Associated Application is found or not)
  497. //
  498. // History: 7-15-96 AdriaanC (Adriaan Canter) Created
  499. //
  500. // Notes:
  501. //
  502. //----------------------------------------------------------------------------
  503. BOOL CContentAnalyzer::FindAppFromExt(LPSTR pszExt, LPSTR pszCommand, DWORD cbCommand)
  504. {
  505. DEBUG_ENTER((DBG_TRANS,
  506. Bool,
  507. "CContentAnalyzer::FindAppFromExt",
  508. "this=%#x, %.80q, %.80q, %d",
  509. this, pszExt, pszCommand, cbCommand
  510. ));
  511. DWORD cbLen, dwType;
  512. CHAR szRegPath[MAX_PATH];
  513. BOOL fReturn = FALSE;
  514. HKEY hMimeKey = NULL;
  515. // BUGBUG - Is there a max registry path length?
  516. cbLen = MAX_PATH;
  517. // Should be a file extension
  518. TransAssert((pszExt[0] == '.'));
  519. // Open key on extension
  520. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, pszExt, 0,
  521. KEY_QUERY_VALUE, &hMimeKey) == ERROR_SUCCESS)
  522. {
  523. // Find file type (txtfile, htmlfile, etc) .
  524. // These currently utilize a null key.
  525. if (RegQueryValueEx(hMimeKey, NULL, NULL, &dwType,
  526. (LPBYTE)szRegPath, &cbLen) == ERROR_SUCCESS)
  527. {
  528. strncat(szRegPath, szApplicationRegistryKey, MAX_PATH - strlen(szRegPath) - 1);
  529. HKEY hAppKey = NULL;
  530. cbLen = cbCommand;
  531. // szRegPath should now look similar to
  532. // "txtfile\Shell\Open\Command". Open key on szRegPath
  533. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szRegPath, 0,
  534. KEY_QUERY_VALUE, &hAppKey) == ERROR_SUCCESS)
  535. {
  536. // Find the application command line - again, null key.
  537. if (RegQueryValueEx(hMimeKey, NULL, NULL, &dwType,
  538. (LPBYTE)pszCommand, &cbLen) == ERROR_SUCCESS)
  539. {
  540. // Success
  541. fReturn = TRUE;
  542. }
  543. RegCloseKey(hAppKey);
  544. }
  545. else
  546. {
  547. // check "Shell\\Connect To\command" key - used by SmartTerm
  548. // dynamic allocate szRegPath2 so that it won't take
  549. // unnecessary stack space - after all, this is not a
  550. // common case
  551. CHAR* szRegPath2 = NULL;
  552. HKEY hAppKey2 = NULL;
  553. szRegPath2 = new CHAR[MAX_PATH];
  554. if( szRegPath2 )
  555. {
  556. if (RegQueryValueEx(hMimeKey, NULL, NULL, &dwType,
  557. (LPBYTE)szRegPath2, &cbLen) == ERROR_SUCCESS)
  558. {
  559. strncat(szRegPath2, szApplicationRegistryKey2,
  560. MAX_PATH - strlen(szRegPath2) - 1);
  561. }
  562. else
  563. {
  564. // this should not happen at all
  565. delete [] szRegPath2;
  566. szRegPath2 = NULL;
  567. }
  568. }
  569. if (szRegPath2 &&
  570. RegOpenKeyEx(HKEY_CLASSES_ROOT, szRegPath2, 0, KEY_QUERY_VALUE, &hAppKey2) == ERROR_SUCCESS)
  571. {
  572. if (RegQueryValueEx(hMimeKey, NULL, NULL, &dwType,
  573. (LPBYTE)pszCommand, &cbLen) == ERROR_SUCCESS)
  574. {
  575. // Success
  576. fReturn = TRUE;
  577. }
  578. RegCloseKey(hAppKey2);
  579. }
  580. delete [] szRegPath2;
  581. }
  582. }
  583. RegCloseKey(hMimeKey);
  584. }
  585. DEBUG_LEAVE(fReturn);
  586. return fReturn;
  587. }
  588. //+---------------------------------------------------------------------------
  589. //
  590. // Method: CContentAnalyzer::CheckTextHeaders
  591. //
  592. // Synopsis:
  593. //
  594. //
  595. // Arguments: void
  596. //
  597. // Returns: void
  598. //
  599. // History: 7-23-96 AdriaanC (Adriaan Canter) Created
  600. //
  601. // Notes:
  602. //
  603. //----------------------------------------------------------------------------
  604. BOOL CContentAnalyzer::CheckTextHeaders()
  605. {
  606. DEBUG_ENTER((DBG_TRANS,
  607. Bool,
  608. "CContentAnalyzer::CheckTextHeaders",
  609. "this=%#x",
  610. this
  611. ));
  612. BOOL bRet = TRUE;
  613. // application/pdf (Acrobat)
  614. if (!StrCmpNC(_pBuf, vszPdfMagic, sizeof(vszPdfMagic) - 1))
  615. {
  616. _wzMimeType = vwzApplicationPdf;
  617. }
  618. // application/Postscript
  619. else if (!StrCmpNC(_pBuf, vszPostscriptMagic, sizeof(vszPostscriptMagic) - 1))
  620. {
  621. _wzMimeType = vwzApplicationPostscript;
  622. }
  623. // text/richtext
  624. else if (!StrCmpNC(_pBuf, vszRichTextMagic, sizeof(vszRichTextMagic) - 1))
  625. {
  626. _wzMimeType = vwzTextRichText;
  627. }
  628. // application/base64
  629. else if (!StrCmpNC(_pBuf, vszBase64Magic, sizeof(vszBase64Magic) - 1))
  630. {
  631. _wzMimeType = vwzApplicationBase64;
  632. }
  633. // No matches - assume plain text.
  634. else
  635. {
  636. //_wzMimeType = vwzTextPlain;
  637. bRet = FALSE;
  638. }
  639. DEBUG_LEAVE(bRet);
  640. return bRet;
  641. }
  642. //+---------------------------------------------------------------------------
  643. //
  644. // Method: CContentAnalyzer::CheckBinaryHeaders
  645. //
  646. // Synopsis:
  647. //
  648. //
  649. // Arguments: void
  650. //
  651. // Returns: void
  652. //
  653. // History: 7-23-96 AdriaanC (Adriaan Canter) Created
  654. //
  655. // Notes:
  656. //
  657. //----------------------------------------------------------------------------
  658. BOOL CContentAnalyzer::CheckBinaryHeaders()
  659. {
  660. DEBUG_ENTER((DBG_TRANS,
  661. Bool,
  662. "CContentAnalyzer::CheckBinaryHeaders",
  663. "this=%#x",
  664. this
  665. ));
  666. BOOL bRet = TRUE;
  667. // image/gif
  668. if (!StrCmpNIC(_pBuf, vszGif87Magic, sizeof(vszGif87Magic) - 1)
  669. || !StrCmpNIC(_pBuf, vszGif89Magic, sizeof(vszGif89Magic) - 1))
  670. {
  671. _wzMimeType = vwzImageGif;
  672. }
  673. // image/pjpeg
  674. else if ((BYTE)_pBuf[0] == JPEG_MAGIC_1 && (BYTE)_pBuf[1] == JPEG_MAGIC_2)
  675. {
  676. _wzMimeType = vwzImagePJpeg;
  677. }
  678. // img/bmp
  679. else if (IsBMP())
  680. {
  681. _wzMimeType = vwzImageBmp;
  682. }
  683. // audio/wav
  684. else if (MatchDWordAtOffset(RIFF_MAGIC, 0)
  685. && MatchDWordAtOffset(WAV_MAGIC, 8))
  686. {
  687. _wzMimeType = vwzAudioWav;
  688. }
  689. // audio/basic (.au files)
  690. else if (MatchDWordAtOffset(AU_DEC_MAGIC, 0)
  691. || MatchDWordAtOffset(AU_SUN_MAGIC, 0)
  692. || MatchDWordAtOffset(AU_DEC_INV_MAGIC, 0)
  693. || MatchDWordAtOffset(AU_SUN_INV_MAGIC, 0))
  694. {
  695. _wzMimeType = vwzAudioBasic;
  696. }
  697. // image/tiff
  698. else if (!StrCmpC(_pBuf, vszTiffMagic)) // "MM" followed by a \0
  699. {
  700. _wzMimeType = vwzImageTiff;
  701. }
  702. // application/x-msdownload
  703. else if (!StrCmpNC(_pBuf, vszExeMagic, sizeof(vszExeMagic) - 1))
  704. {
  705. _wzMimeType = vwzApplicationMSDownload;
  706. }
  707. // image/x-png
  708. else if (!StrCmpNC(_pBuf, vszPngMagic, sizeof(vszPngMagic) - 1))
  709. {
  710. _wzMimeType = vwzImagePng;
  711. }
  712. // image/x-jg
  713. else if (!StrCmpNC(_pBuf, vszJGMagic, sizeof(vszJGMagic) - 1)
  714. && (int) _pBuf[2] >= 3
  715. && (int) _pBuf[2] <= 31
  716. && _pBuf[4] == 0)
  717. {
  718. _wzMimeType = vwzImageJG;
  719. }
  720. // audio/x-aiff
  721. else if (MatchDWordAtOffset(AIFF_INV_MAGIC, 0))
  722. {
  723. _wzMimeType = vwzAudioAiff;
  724. }
  725. else if (MatchDWordAtOffset(AIFF_MAGIC, 0) &&
  726. ( MatchDWordAtOffset(AIFF_MAGIC_MORE_1, 8) ||
  727. MatchDWordAtOffset(AIFF_MAGIC_MORE_2, 8) ) )
  728. {
  729. //
  730. // according to DaveMay, the correct AIFF format would be:
  731. // 'FORM....AIFF' or 'FORM....AIFC'
  732. // Only check for 'FORM' is incorrect because .sc2 has the
  733. // same sig
  734. //
  735. _wzMimeType = vwzAudioAiff;
  736. }
  737. // video/avi (or video/x-msvedio)
  738. else if (MatchDWordAtOffset(RIFF_MAGIC, 0)
  739. && MatchDWordAtOffset(AVI_MAGIC, 8))
  740. {
  741. _wzMimeType = vwzVideoAvi;
  742. }
  743. // video/mpeg
  744. else if (MatchDWordAtOffset(MPEG_MAGIC, 0)
  745. || MatchDWordAtOffset(MPEG_MAGIC_2, 0) )
  746. {
  747. _wzMimeType = vwzVideoMpeg;
  748. }
  749. // image/x-emf
  750. else if (MatchDWordAtOffset(EMF_MAGIC_1, 0)
  751. && MatchDWordAtOffset(EMF_MAGIC_2, 40))
  752. {
  753. _wzMimeType = vwzImageEmf;
  754. }
  755. // image/x-wmf
  756. else if (MatchDWordAtOffset(WMF_MAGIC, 0))
  757. {
  758. _wzMimeType = vwzImageWmf;
  759. }
  760. // application/java
  761. else if (MatchDWordAtOffset(JAVA_MAGIC, 0))
  762. {
  763. _wzMimeType = vwzApplicationJava;
  764. }
  765. // application/x-zip-compressed
  766. else if (!StrCmpNC(_pBuf, vszZipMagic, sizeof(vszZipMagic) - 1))
  767. {
  768. _wzMimeType = vwzApplicationZipCompressed;
  769. }
  770. // application/x-compress
  771. else if (!StrCmpNC(_pBuf, vszCompressMagic, sizeof(vszCompressMagic) - 1))
  772. {
  773. _wzMimeType = vwzApplicationCompressed;
  774. }
  775. // application/x-gzip
  776. else if (!StrCmpNC(_pBuf, vszGzipMagic, sizeof(vszGzipMagic) - 1))
  777. {
  778. _wzMimeType = vwzApplicationGzipCompressed;
  779. }
  780. // application/x-zip-compressed
  781. else if (!StrCmpNC(_pBuf, vszZipMagic, sizeof(vszZipMagic) - 1))
  782. {
  783. _wzMimeType = vwzApplicationZipCompressed;
  784. }
  785. // audio/mid
  786. else if (!StrCmpC(_pBuf, vszMIDMagic))
  787. {
  788. _wzMimeType = vwzAudioMID;
  789. }
  790. // application/pdf (Acrobat)
  791. else if (!StrCmpNC(_pBuf, vszPdfMagic, sizeof(vszPdfMagic) - 1))
  792. {
  793. _wzMimeType = vwzApplicationPdf;
  794. }
  795. // don't know what it is.
  796. else
  797. {
  798. //_wzMimeType = vwzApplicationOctetStream;
  799. bRet = FALSE;
  800. }
  801. DEBUG_LEAVE(bRet);
  802. return bRet;
  803. }
  804. //+---------------------------------------------------------------------------
  805. //
  806. // Method: CContentAnalyzer::FindMimeFromData
  807. //
  808. // Synopsis: Attempts to guess MIME type from buffer
  809. //
  810. //
  811. // Arguments: pBuf, cbSample, wzSuggestedMimeType
  812. //
  813. // Returns: LPCWSTR (the MIME type guessed)
  814. //
  815. // History: 5-25-96 AdriaanC (Adriaan Canter) Created
  816. //
  817. // Notes:
  818. //
  819. //----------------------------------------------------------------------------
  820. LPCWSTR CContentAnalyzer::FindMimeFromData(LPCWSTR wzFileName, char* pBuf,
  821. int cbSample, LPCWSTR wzSuggestedMimeType, DWORD grfFlags)
  822. {
  823. DEBUG_ENTER((DBG_TRANS,
  824. Pointer,
  825. "CContentAnalyzer::FindMimeFromData",
  826. "this=%#x, %.80wq, %.80q, %d, %.80wq, %#x",
  827. this, wzFileName, pBuf, cbSample, wzSuggestedMimeType, grfFlags
  828. ));
  829. BOOL fSampledData = FALSE;
  830. BOOL fFoundMimeTypeFromExt = FALSE;
  831. CHAR* szFileExt = 0;
  832. CHAR szFileName[MAX_PATH];
  833. CHAR szMimeTypeFromExt[SZMIMESIZE_MAX];
  834. CHAR szCommand[MAX_PATH];
  835. CHAR cLastByte;
  836. DWORD dwMimeLen = SZMIMESIZE_MAX;
  837. DWORD dwExtMimeTypeDataFormat;
  838. DWORD dwSuggestedMimeTypeDataFormat;
  839. DWORD dwMimeTypeDataFormat;
  840. DWORD cbCommand = MAX_PATH;
  841. BOOL fExtensionChecked = FALSE;
  842. _grfFlags = grfFlags;
  843. // BUGBUG - we can use this information for DBCS.
  844. // Remove any info appended to the suggested mime type
  845. // such as charset information. This is identified by ';'
  846. if (wzSuggestedMimeType)
  847. {
  848. WCHAR* wptr = wcsstr(wzSuggestedMimeType, L";");
  849. if (wptr)
  850. {
  851. *wptr = L'\0';
  852. }
  853. }
  854. // Check to see if the server is suggesting an unknown mime type
  855. dwSuggestedMimeTypeDataFormat = GetDataFormat(wzSuggestedMimeType);
  856. if (dwSuggestedMimeTypeDataFormat == DATAFORMAT_UNKNOWN)
  857. {
  858. // server push returns "multipart" content type
  859. // this is not the real mimetype, so we have to sniff
  860. // to find out the truth
  861. if( wcsicmp(wzSuggestedMimeType, vwzmultipartmixed)
  862. && wcsicmp(wzSuggestedMimeType, vwzmultipartmixedreplace) )
  863. {
  864. // If so, return the suggested mime type.
  865. _wzMimeType = (WCHAR*) wzSuggestedMimeType;
  866. DEBUG_LEAVE(_wzMimeType);
  867. return _wzMimeType;
  868. }
  869. }
  870. /*****
  871. // check if we got an extension and extension mime
  872. // matches the suggested mime - only for text/plain
  873. if ( wzSuggestedMimeType
  874. && wzFileName
  875. && !wcscmp(wzSuggestedMimeType,vwzTextPlain))
  876. {
  877. fExtensionChecked = TRUE;
  878. fFoundMimeTypeFromExt = FindMimeFromExt(
  879. wzFileName,
  880. szFileName,
  881. szMimeTypeFromExt,
  882. &dwExtMimeTypeDataFormat,
  883. &szFileExt
  884. );
  885. // If there is a mime type associated with the file
  886. // extension then return it.
  887. if ( fFoundMimeTypeFromExt
  888. && (dwExtMimeTypeDataFormat == dwSuggestedMimeTypeDataFormat)
  889. && !wcscmp(wzSuggestedMimeType,_wzMimeTypeFromExt)
  890. )
  891. {
  892. // If so, return the suggested mime type.
  893. _wzMimeType = (WCHAR*) wzSuggestedMimeType;
  894. return _wzMimeType;
  895. }
  896. }
  897. *****/
  898. // Not enough data to tell anything
  899. if (!pBuf || cbSample <= 0)
  900. {
  901. _wzMimeType = (WCHAR*) wzSuggestedMimeType;
  902. DEBUG_LEAVE(_wzMimeType);
  903. return _wzMimeType;
  904. }
  905. _pBuf = pBuf;
  906. _cbSample = (cbSample <= SAMPLE_SIZE) ? cbSample : SAMPLE_SIZE;
  907. // Save off last character. Null terminate the buffer.
  908. cLastByte = _pBuf[_cbSample - 1];
  909. _pBuf[_cbSample - 1] = '\0';
  910. // Common cases first - check the server indicated mime type
  911. // for text/html, image/gif or image/[p]jpeg.
  912. if ( wzSuggestedMimeType
  913. && !StrCmpICW(wzSuggestedMimeType, vwzTextHTML))
  914. {
  915. // Sample the data. This routine also checks for the following
  916. // mime types which require extended scanning through the buffer:
  917. // text/html, image/x-xbitmap, application/macbinhex
  918. SampleData();
  919. fSampledData = TRUE;
  920. if (_fFoundHTML)
  921. {
  922. _wzMimeType = vwzTextHTML;
  923. goto exit;
  924. }
  925. }
  926. // image/gif
  927. else if (wzSuggestedMimeType
  928. && !wcsicmp(wzSuggestedMimeType, vwzImageGif))
  929. {
  930. if (!StrCmpNIC(_pBuf, vszGif87Magic, sizeof(vszGif87Magic) - 1)
  931. || !StrCmpNIC(_pBuf, vszGif89Magic, sizeof(vszGif89Magic) - 1))
  932. {
  933. _wzMimeType = vwzImageGif;
  934. goto exit;
  935. }
  936. }
  937. // image/jpeg or image/pjpeg
  938. else if (wzSuggestedMimeType
  939. && (!wcsicmp(wzSuggestedMimeType, vwzImagePJpeg)
  940. || !wcsicmp(wzSuggestedMimeType, vwzImageJpeg)))
  941. {
  942. if ((BYTE)_pBuf[0] == JPEG_MAGIC_1 && (BYTE)_pBuf[1] == JPEG_MAGIC_2)
  943. {
  944. _wzMimeType = vwzImagePJpeg;
  945. goto exit;
  946. }
  947. }
  948. //
  949. // ********************** BEGIN HACK *******************************
  950. //
  951. // we will remove this once tridents defined the unique signature
  952. // for .hta and .htc format
  953. //
  954. // DanpoZ (98.08.12) - refer to IE5 SUPERHOT bug 35478
  955. //
  956. if (wzFileName )
  957. {
  958. CHAR* szExt;
  959. CHAR szFile[MAX_PATH];
  960. W2A(wzFileName, szFile, MAX_PATH);
  961. if( grfFlags & FMFD_URLASFILENAME )
  962. {
  963. //
  964. // remove teh security context '\1' and replace it with '\0'
  965. // but only do this when we are using URL to replace the filename
  966. //
  967. CHAR* pch = StrChr(szFile, '\1');
  968. if (pch)
  969. {
  970. *pch = '\0';
  971. }
  972. }
  973. szExt = FindFileExtension(szFile);
  974. if( szExt &&
  975. ( !StrCmpNIC(szExt, ".hta", sizeof(".hta") - 1) ||
  976. !StrCmpNIC(szExt, ".htc", sizeof(".htc") - 1) ) )
  977. {
  978. fExtensionChecked = TRUE;
  979. fFoundMimeTypeFromExt = FindMimeFromExt(
  980. wzFileName,
  981. szFileName,
  982. szMimeTypeFromExt,
  983. &dwExtMimeTypeDataFormat,
  984. &szFileExt
  985. );
  986. // If there is a mime type associated with the file
  987. // extension then return it.
  988. if (fFoundMimeTypeFromExt)
  989. {
  990. _wzMimeType = _wzMimeTypeFromExt;
  991. goto exit;
  992. }
  993. }
  994. }
  995. //
  996. // ********************** END HACK *********************************
  997. //
  998. // One of the following is true:
  999. // 1) The server indicated a common mime type (html, gif or jpeg),
  1000. // however, verification failed.
  1001. // 2) The server indicated an ambiguous mime type or
  1002. // a known, but uncommon mime type.
  1003. // If not done so already, sample the data.
  1004. if (!fSampledData)
  1005. {
  1006. SampleData();
  1007. fSampledData = TRUE;
  1008. }
  1009. // Return any mime type that was positively
  1010. // identified during the data sampling
  1011. if( _fFoundCDF )
  1012. {
  1013. _wzMimeType = vwzApplicationCDF;
  1014. goto exit;
  1015. }
  1016. else if( _fFoundXML)
  1017. {
  1018. _wzMimeType = vwzTextXML;
  1019. goto exit;
  1020. }
  1021. else if (_fFoundHTML)
  1022. {
  1023. _wzMimeType = vwzTextHTML;
  1024. goto exit;
  1025. }
  1026. else if (_fFoundXBitMap)
  1027. {
  1028. _wzMimeType = vwzImageXBitmap;
  1029. goto exit;
  1030. }
  1031. else if (_fFoundMacBinhex)
  1032. {
  1033. _wzMimeType = vwzApplicationMacBinhex;
  1034. goto exit;
  1035. }
  1036. else if( _fFoundTextScriptlet )
  1037. {
  1038. _wzMimeType = vwzTextScriptlet;
  1039. goto exit;
  1040. }
  1041. if( !_fFoundCDF
  1042. && wzSuggestedMimeType
  1043. && !wcsicmp(wzSuggestedMimeType, vwzApplicationNETCDF)
  1044. )
  1045. {
  1046. // only overwrite application/x-netcdf with aplication/x-cdf
  1047. _wzMimeType = vwzApplicationNETCDF;
  1048. goto exit;
  1049. }
  1050. // Decide if buffer is primarily text or binary. Conduct
  1051. // pattern matching to determine a mime type depending on the
  1052. // finding.
  1053. if (!_cbCtrl || _cbText + _cbFF >= 16 * (_cbCtrl + _cbHigh))
  1054. {
  1055. _fBinary = FALSE;
  1056. if( !CheckTextHeaders() )
  1057. {
  1058. if( !CheckBinaryHeaders() )
  1059. {
  1060. _wzMimeType = vwzTextPlain;
  1061. }
  1062. }
  1063. }
  1064. else
  1065. {
  1066. _fBinary = TRUE;
  1067. if( !CheckBinaryHeaders() )
  1068. {
  1069. if( !CheckTextHeaders() )
  1070. {
  1071. _wzMimeType = vwzApplicationOctetStream;
  1072. }
  1073. }
  1074. }
  1075. // Determine format of the mime type from data
  1076. dwMimeTypeDataFormat = GetDataFormat(_wzMimeType);
  1077. // If the format of the mime type found from examining the data
  1078. // is not ambiguous, then return this mime type.
  1079. if (dwMimeTypeDataFormat != DATAFORMAT_AMBIGUOUS)
  1080. {
  1081. goto exit;
  1082. }
  1083. // Examination of data is inconclusive.
  1084. else
  1085. {
  1086. // If the suggested mime type is not ambiguous and does
  1087. // not conflict with the data format then return it.
  1088. if (dwSuggestedMimeTypeDataFormat != DATAFORMAT_AMBIGUOUS
  1089. && FormatAgreesWithData(dwSuggestedMimeTypeDataFormat))
  1090. {
  1091. _wzMimeType = (WCHAR*) wzSuggestedMimeType;
  1092. goto exit;
  1093. }
  1094. // Otherwise, attempt to obtain a mime type from any
  1095. // file extension. If none is found, but an application
  1096. // is registered for the file extension, return
  1097. // application/octet-stream.
  1098. // If there is a file extension, find any
  1099. // associated mime type.
  1100. if (wzFileName && !fExtensionChecked)
  1101. {
  1102. fExtensionChecked = TRUE;
  1103. fFoundMimeTypeFromExt = FindMimeFromExt(
  1104. wzFileName,
  1105. szFileName,
  1106. szMimeTypeFromExt,
  1107. &dwExtMimeTypeDataFormat,
  1108. &szFileExt
  1109. );
  1110. }
  1111. // If there is a mime type associated with the file
  1112. // extension then return it.
  1113. if (fFoundMimeTypeFromExt)
  1114. {
  1115. if (dwExtMimeTypeDataFormat == DATAFORMAT_UNKNOWN)
  1116. {
  1117. _wzMimeType = _wzMimeTypeFromExt;
  1118. goto exit;
  1119. }
  1120. else
  1121. {
  1122. goto exit;
  1123. }
  1124. }
  1125. // Otherwise, check to see if there is an associated application.
  1126. if (szFileExt && FindAppFromExt(szFileExt, szCommand, cbCommand))
  1127. {
  1128. // Found an associated application.
  1129. _wzMimeType = vwzApplicationOctetStream;
  1130. goto exit;
  1131. }
  1132. // No suggested mime type, no mime type from file extension
  1133. // and no registered application found. Fall through and return
  1134. // mime type found from the data
  1135. }
  1136. exit:
  1137. // Replace the null termination with
  1138. // the original character.
  1139. _pBuf[_cbSample - 1] = cLastByte;
  1140. DEBUG_LEAVE(_wzMimeType);
  1141. return _wzMimeType;
  1142. }
  1143. //+---------------------------------------------------------------------------
  1144. //
  1145. // Method: CContentAnalyzer::FindMimeFromExt
  1146. //
  1147. // Synopsis:
  1148. //
  1149. // Arguments: [wzFileName] --
  1150. // [szFileName] --
  1151. // [szMimeTypeFromExt] --
  1152. // [pdwExtMimeTypeDataFormat] --
  1153. //
  1154. // Returns:
  1155. //
  1156. // History: 5-25-96 AdriaanC (Adriaan Canter)
  1157. // 1-28-1997 JohannP (Johann Posch) made separate function
  1158. //
  1159. // Notes:
  1160. //
  1161. //----------------------------------------------------------------------------
  1162. BOOL CContentAnalyzer::FindMimeFromExt(
  1163. LPCWSTR wzFileName,
  1164. CHAR *szFileName,
  1165. CHAR *szMimeTypeFromExt,
  1166. DWORD *pdwExtMimeTypeDataFormat,
  1167. CHAR **ppszFileExt)
  1168. {
  1169. DEBUG_ENTER((DBG_TRANS,
  1170. Bool,
  1171. "CContentAnalyzer::FindMimeFromExt",
  1172. "this=%#x, %.80wq, %.80q, %.80q, %#x, %#x",
  1173. this, wzFileName, szFileName, szMimeTypeFromExt, pdwExtMimeTypeDataFormat, ppszFileExt
  1174. ));
  1175. BOOL fFoundMimeTypeFromExt = FALSE;
  1176. UrlMkAssert((wzFileName && szFileName && pdwExtMimeTypeDataFormat));
  1177. DWORD dwMimeLen = SZMIMESIZE_MAX;
  1178. CHAR* szFileExt = 0;
  1179. // If there is a file extension, find any
  1180. // associated mime type.
  1181. W2A(wzFileName, szFileName, MAX_PATH);
  1182. szFileExt = FindFileExtension(szFileName);
  1183. if (szFileExt && GetMimeFromExt(szFileExt,
  1184. szMimeTypeFromExt, &dwMimeLen) == ERROR_SUCCESS)
  1185. {
  1186. fFoundMimeTypeFromExt = TRUE;
  1187. A2W(szMimeTypeFromExt, _wzMimeTypeFromExt, SZMIMESIZE_MAX);
  1188. *pdwExtMimeTypeDataFormat = GetDataFormat(_wzMimeTypeFromExt);
  1189. }
  1190. if (szFileExt && ppszFileExt)
  1191. {
  1192. *ppszFileExt = szFileExt;
  1193. }
  1194. DEBUG_LEAVE(fFoundMimeTypeFromExt);
  1195. return fFoundMimeTypeFromExt;
  1196. }