Source code of Windows XP (NT5)
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.

1152 lines
26 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. CheckBmp.cpp
  5. Abstract:
  6. BMP file format checking routines
  7. Author:
  8. Hakki T. Bostanci (hakkib) 17-Dec-1999
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #include "Wrappers.h"
  13. #include "LogWindow.h"
  14. #include "LogWrappers.h"
  15. #include "Argv.h"
  16. #include "CheckBmp.h"
  17. #ifdef _CONSOLE
  18. TCHAR szDecVal[] = _T("%-15s = %d");
  19. TCHAR szHexVal[] = _T("%-15s = 0x%08x");
  20. TCHAR szStrVal[] = _T("%-15s = %s");
  21. TCHAR szDblVal[] = _T("%-15s = %.4lf");
  22. #else //_CONSOLE
  23. TCHAR szDecVal[] = _T("%s = %d");
  24. TCHAR szHexVal[] = _T("%s = 0x%08x");
  25. TCHAR szStrVal[] = _T("%s = %s");
  26. TCHAR szDblVal[] = _T("%s = %.4lf");
  27. #endif //_CONSOLE
  28. //////////////////////////////////////////////////////////////////////////
  29. //
  30. // HeaderSize
  31. //
  32. // Routine Description:
  33. // returns the size of the bitmap header
  34. //
  35. // Arguments:
  36. //
  37. // Return Value:
  38. //
  39. inline
  40. DWORD
  41. HeaderSize(
  42. const VOID *pBitmapInfo
  43. )
  44. {
  45. return *(PDWORD)pBitmapInfo;
  46. }
  47. //////////////////////////////////////////////////////////////////////////
  48. //
  49. // WidthBytes
  50. //
  51. // Routine Description:
  52. // calculates the number of bytes in a BMP row (that should be DWORD aligned)
  53. //
  54. // Arguments:
  55. //
  56. // Return Value:
  57. //
  58. inline
  59. DWORD
  60. WidthBytes(
  61. DWORD dwWidth,
  62. DWORD dwBitCount
  63. )
  64. {
  65. return (((dwWidth * dwBitCount) + 31) & ~31) >> 3;
  66. }
  67. //////////////////////////////////////////////////////////////////////////
  68. //
  69. // FXPT_TO_FLPT, FXPT2DOT30_TO_FLPT, FXPT16DOT16_TO_FLPT
  70. //
  71. // Routine Description:
  72. // floating point to fixed point conversion macros
  73. //
  74. // Arguments:
  75. //
  76. // Return Value:
  77. //
  78. inline
  79. double
  80. FXPT_TO_FLPT(
  81. long nFixed,
  82. int nPoint
  83. )
  84. {
  85. double nInteger = nFixed >> nPoint;
  86. double nFraction = ldexp(nFixed & ((1 << nPoint) - 1), -nPoint);
  87. return nInteger + nFraction;
  88. }
  89. inline
  90. double
  91. FXPT2DOT30_TO_FLPT(
  92. FXPT2DOT30 nFixed
  93. )
  94. {
  95. return FXPT_TO_FLPT(nFixed, 30);
  96. }
  97. inline
  98. double
  99. FXPT16DOT16_TO_FLPT(
  100. FXPT16DOT16 nFixed
  101. )
  102. {
  103. return FXPT_TO_FLPT(nFixed, 16);
  104. }
  105. //////////////////////////////////////////////////////////////////////////
  106. //
  107. // Contiguous
  108. //
  109. // Routine Description:
  110. // Tests whether the 1's are contiguous in an integers, i.e. 00000111,
  111. // 00011100, 11100000, 00000000, 11111111 are OK but 00101100 is not
  112. //
  113. // Arguments:
  114. //
  115. // Return Value:
  116. //
  117. template <class T>
  118. BOOL Contiguous(T Bits)
  119. {
  120. const NumBits = sizeof(T) * 8;
  121. T i = 0;
  122. while (i < NumBits && (Bits & (1 << i)) == 0) ++i;
  123. while (i < NumBits && (Bits & (1 << i)) != 0) ++i;
  124. while (i < NumBits && (Bits & (1 << i)) == 0) ++i;
  125. return i == NumBits;
  126. }
  127. //////////////////////////////////////////////////////////////////////////
  128. //
  129. // CheckColorMasks
  130. //
  131. // Routine Description:
  132. // checks the validity of the color masks in a bitfields type bmp.
  133. // the masks should not overlap and the bits should be contiguous
  134. // within each map
  135. //
  136. // Arguments:
  137. //
  138. // Return Value:
  139. //
  140. BOOL
  141. CheckColorMasks(
  142. DWORD dwRedMask,
  143. DWORD dwGreenMask,
  144. DWORD dwBlueMask
  145. )
  146. {
  147. return
  148. (dwRedMask & dwGreenMask) == 0 &&
  149. (dwRedMask & dwBlueMask) == 0 &&
  150. (dwGreenMask & dwBlueMask) == 0 &&
  151. Contiguous(dwRedMask) &&
  152. Contiguous(dwGreenMask) &&
  153. Contiguous(dwBlueMask);
  154. }
  155. //////////////////////////////////////////////////////////////////////////
  156. //
  157. //
  158. //
  159. // Routine Description:
  160. // compares two RGBTRIPLE's
  161. //
  162. // Arguments:
  163. //
  164. // Return Value:
  165. //
  166. inline bool __cdecl operator <(const RGBTRIPLE &lhs, const RGBTRIPLE &rhs)
  167. {
  168. return
  169. RGB(lhs.rgbtRed, lhs.rgbtGreen, lhs.rgbtBlue) <
  170. RGB(rhs.rgbtRed, rhs.rgbtGreen, rhs.rgbtBlue);
  171. }
  172. //////////////////////////////////////////////////////////////////////////
  173. //
  174. //
  175. //
  176. // Routine Description:
  177. //
  178. //
  179. // Arguments:
  180. //
  181. // Return Value:
  182. //
  183. inline void __cdecl LOG_INFO(PCTSTR pFormat, ...)
  184. {
  185. va_list arglist;
  186. va_start(arglist, pFormat);
  187. g_pLog->LogV(TLS_INFO | TLS_VARIATION, 0, 0, pFormat, arglist);
  188. }
  189. inline void __cdecl LOG_ERROR(DWORD dwLogLevel, PCTSTR pFormat, ...)
  190. {
  191. va_list arglist;
  192. va_start(arglist, pFormat);
  193. g_pLog->LogV(dwLogLevel | TLS_VARIATION, 0, 0, pFormat, arglist);
  194. }
  195. //////////////////////////////////////////////////////////////////////////
  196. //
  197. // CheckBmp
  198. //
  199. // Routine Description:
  200. // Main entry point for this module. Checks the validity of a BMP
  201. // file or an in-memory image.
  202. //
  203. // Arguments:
  204. //
  205. // Return Value:
  206. //
  207. BOOL CheckBmp(PVOID pDIB, DWORD dwDIBSize, BOOL bSkipFileHeader)
  208. {
  209. return CCheckBmp().Check(pDIB, dwDIBSize, bSkipFileHeader);
  210. }
  211. BOOL CheckBmp(PCTSTR pszFileName)
  212. {
  213. CInFile TheFile(pszFileName);
  214. CFileMapping TheMap(TheFile, 0, PAGE_READONLY);
  215. CMapViewOfFile<VOID> TheData(TheMap, FILE_MAP_READ);
  216. return CCheckBmp().Check(TheData, GetFileSize(TheFile, 0), FALSE);
  217. }
  218. //////////////////////////////////////////////////////////////////////////
  219. //
  220. // CCheckBmp::Check
  221. //
  222. // Routine Description:
  223. //
  224. // Arguments:
  225. //
  226. // Return Value:
  227. //
  228. CCheckBmp::Check(PVOID pDIB, DWORD dwDIBSize, BOOL bSkipFileHeader)
  229. {
  230. ZeroMemory(this, sizeof(*this));
  231. LOG_INFO(szDecVal, _T("DibSize"), dwDIBSize);
  232. m_pDIB = pDIB;
  233. m_nDIBSize = dwDIBSize;
  234. return
  235. (bSkipFileHeader || CheckFileHeader()) &&
  236. CheckBitmapInfo() &&
  237. CheckPalette() &&
  238. CheckPixelData();
  239. }
  240. //////////////////////////////////////////////////////////////////////////
  241. //
  242. // CCheckBmp::CheckFileHeader
  243. //
  244. // Routine Description:
  245. // Checks BITMAPFILEHEADER
  246. //
  247. // Arguments:
  248. //
  249. // Return Value:
  250. //
  251. BOOL CCheckBmp::CheckFileHeader()
  252. {
  253. BOOL bResult = TRUE;
  254. m_pFileHeader = m_pDIB;
  255. m_nFileHeaderSize = sizeof(BITMAPFILEHEADER);
  256. PBITMAPFILEHEADER pbmfh = (PBITMAPFILEHEADER) m_pDIB;
  257. // bfType
  258. // should read "BM"
  259. LOG_INFO(szHexVal, _T("Type"), pbmfh->bfType);
  260. if (LOBYTE(pbmfh->bfType) != 'B' || HIBYTE(pbmfh->bfType) != 'M')
  261. {
  262. LOG_ERROR(TLS_SEV2, _T("Unexpected bitmap file type"));
  263. bResult = FALSE;
  264. }
  265. // bfSize
  266. // should equal file size
  267. LOG_INFO(szDecVal, _T("Size"), pbmfh->bfSize);
  268. if (pbmfh->bfSize != m_nDIBSize)
  269. {
  270. LOG_ERROR(TLS_SEV2, _T("Unexpected bitmap file size"));
  271. bResult = FALSE;
  272. }
  273. // bfReserved1, bfReserved2
  274. // should be zero
  275. LOG_INFO(szDecVal, _T("Reserved1"), pbmfh->bfReserved1);
  276. LOG_INFO(szDecVal, _T("Reserved2"), pbmfh->bfReserved2);
  277. if (pbmfh->bfReserved1 != 0 || pbmfh->bfReserved2 != 0)
  278. {
  279. LOG_ERROR(TLS_SEV2, _T("Unexpected Reserved value"));
  280. bResult = FALSE;
  281. }
  282. // bfOffBits
  283. // will be checked in CheckPixelData
  284. LOG_INFO(szDecVal, _T("OffBits"), pbmfh->bfOffBits);
  285. m_pPixelData = (PBYTE) pbmfh + pbmfh->bfOffBits;
  286. return bResult;
  287. }
  288. //////////////////////////////////////////////////////////////////////////
  289. //
  290. // CCheckBmp::CheckBitmapInfo
  291. //
  292. // Routine Description:
  293. // Checks the bitmap header according to the header size
  294. //
  295. // Arguments:
  296. //
  297. // Return Value:
  298. //
  299. BOOL CCheckBmp::CheckBitmapInfo()
  300. {
  301. BOOL bResult = TRUE;
  302. m_pInfoHeader = (PBYTE) m_pDIB + m_nFileHeaderSize;
  303. PBITMAPINFO pbmi = (PBITMAPINFO) m_pInfoHeader;
  304. m_nInfoHeaderSize = pbmi->bmiHeader.biSize;
  305. LOG_INFO(szDecVal, _T("Size"), pbmi->bmiHeader.biSize);
  306. switch (pbmi->bmiHeader.biSize)
  307. {
  308. case sizeof(BITMAPCOREHEADER):
  309. bResult = CheckBitmapCoreHeader();
  310. break;
  311. case sizeof(BITMAPINFOHEADER):
  312. bResult = CheckBitmapInfoHeader();
  313. break;
  314. case sizeof(BITMAPV4HEADER):
  315. bResult = CheckBitmapV4Header();
  316. break;
  317. case sizeof(BITMAPV5HEADER):
  318. bResult = CheckBitmapV5Header();
  319. break;
  320. default:
  321. LOG_ERROR(TLS_SEV2, _T("Unexpected header size"));
  322. bResult = FALSE;
  323. }
  324. return bResult;
  325. }
  326. //////////////////////////////////////////////////////////////////////////
  327. //
  328. // CCheckBmp::CheckPalette
  329. //
  330. // Routine Description:
  331. // Checks the bitmap color palette
  332. //
  333. // Arguments:
  334. //
  335. // Return Value:
  336. //
  337. BOOL CCheckBmp::CheckPalette()
  338. {
  339. BOOL bResult = TRUE;
  340. m_pPalette = (PBYTE) m_pInfoHeader + m_nInfoHeaderSize;
  341. std::set<RGBTRIPLE> UsedColors;
  342. if (m_nInfoHeaderSize == sizeof(BITMAPCOREHEADER))
  343. {
  344. RGBTRIPLE *prgbt = (RGBTRIPLE *) m_pPalette;
  345. for (int i = 0; i < m_nPaletteSize / sizeof(RGBTRIPLE); ++i)
  346. {
  347. /*LOG_INFO(
  348. _T("Color %3d: R=%02x G=%02x B=%02x"),
  349. i,
  350. prgbt[i].rgbtRed,
  351. prgbt[i].rgbtGreen,
  352. prgbt[i].rgbtBlue
  353. );*/
  354. if (!UsedColors.insert(prgbt[i]).second)
  355. {
  356. LOG_ERROR(
  357. TLS_SEV3,
  358. _T("Repeated palette entry %3d: R=%02x G=%02x B=%02x"),
  359. i,
  360. prgbt[i].rgbtRed,
  361. prgbt[i].rgbtGreen,
  362. prgbt[i].rgbtBlue
  363. );
  364. bResult = FALSE;
  365. }
  366. }
  367. }
  368. else
  369. {
  370. LPRGBQUAD prgbq = (LPRGBQUAD) m_pPalette;
  371. for (int i = 0; i < m_nPaletteSize / sizeof(RGBQUAD); ++i)
  372. {
  373. /*LOG_INFO(
  374. _T("Color %3d: R=%02x G=%02x B=%02x A=%02x"),
  375. i,
  376. prgbq[i].rgbRed,
  377. prgbq[i].rgbGreen,
  378. prgbq[i].rgbBlue,
  379. prgbq[i].rgbReserved
  380. );*/
  381. if (prgbq[i].rgbReserved != 0)
  382. {
  383. LOG_ERROR(
  384. TLS_SEV3,
  385. _T("Unexpected rgbReserved value in palette entry %3d: R=%02x G=%02x B=%02x A=%02x"),
  386. i,
  387. prgbq[i].rgbRed,
  388. prgbq[i].rgbGreen,
  389. prgbq[i].rgbBlue,
  390. prgbq[i].rgbReserved
  391. );
  392. bResult = FALSE;
  393. }
  394. RGBTRIPLE rgbt;
  395. rgbt.rgbtRed = prgbq[i].rgbRed;
  396. rgbt.rgbtGreen = prgbq[i].rgbGreen;
  397. rgbt.rgbtBlue = prgbq[i].rgbBlue;
  398. if (!UsedColors.insert(rgbt).second)
  399. {
  400. LOG_ERROR(
  401. TLS_SEV3,
  402. _T("Repeated palette entry %3d: R=%02x G=%02x B=%02x A=%02x"),
  403. i,
  404. prgbq[i].rgbRed,
  405. prgbq[i].rgbGreen,
  406. prgbq[i].rgbBlue,
  407. prgbq[i].rgbReserved
  408. );
  409. bResult = FALSE;
  410. }
  411. }
  412. }
  413. return bResult;
  414. }
  415. //////////////////////////////////////////////////////////////////////////
  416. //
  417. // CCheckBmp::CheckPixelData
  418. //
  419. // Routine Description:
  420. // Checks the bitmap color palette
  421. //
  422. // Arguments:
  423. //
  424. // Return Value:
  425. //
  426. BOOL CCheckBmp::CheckPixelData()
  427. {
  428. BOOL bResult = TRUE;
  429. PVOID pExpectedPixelData = (PBYTE) m_pPalette + m_nPaletteSize;
  430. if (m_pProfile != 0 && m_pProfile <= pExpectedPixelData)
  431. {
  432. pExpectedPixelData = (PBYTE) m_pProfile + m_nProfileSize;
  433. }
  434. if (m_pPixelData != 0 && m_pPixelData != pExpectedPixelData)
  435. {
  436. LOG_ERROR(TLS_SEV3, _T("Unexpected OffBits value"));
  437. bResult = FALSE;
  438. }
  439. return bResult;
  440. }
  441. //////////////////////////////////////////////////////////////////////////
  442. //
  443. // CCheckBmp::CheckBitmapCoreHeader
  444. //
  445. // Routine Description:
  446. // Checks BITMAPCOREHEADER
  447. //
  448. // Arguments:
  449. //
  450. // Return Value:
  451. //
  452. BOOL CCheckBmp::CheckBitmapCoreHeader()
  453. {
  454. BOOL bResult = TRUE;
  455. PBITMAPCOREHEADER pbih = (PBITMAPCOREHEADER) m_pInfoHeader;
  456. // bcWidth
  457. // should be positive
  458. LOG_INFO(szDecVal, _T("Width"), pbih->bcWidth);
  459. if (pbih->bcWidth <= 0)
  460. {
  461. LOG_ERROR(TLS_SEV2, _T("Unexpected Width value"));
  462. bResult = FALSE;
  463. }
  464. // bcHeight
  465. // should be positive
  466. LOG_INFO(szDecVal, _T("Height"), pbih->bcHeight);
  467. if (pbih->bcHeight <= 0)
  468. {
  469. LOG_ERROR(TLS_SEV2, _T("Unexpected Height value"));
  470. bResult = FALSE;
  471. }
  472. // bcPlanes
  473. // should be 1
  474. LOG_INFO(szDecVal, _T("Planes"), pbih->bcPlanes);
  475. if (pbih->bcPlanes != 1)
  476. {
  477. LOG_ERROR(TLS_SEV2, _T("Unexpected Planes value"));
  478. }
  479. // bcBitCount
  480. // can be 1, 4, 8 or 24
  481. LOG_INFO(szDecVal, _T("BitCount"), pbih->bcBitCount);
  482. switch (pbih->bcBitCount)
  483. {
  484. case 1:
  485. case 4:
  486. case 8:
  487. m_nPaletteSize = (1 << pbih->bcBitCount) * sizeof(RGBTRIPLE);
  488. break;
  489. case 24:
  490. m_nPaletteSize = 0;
  491. break;
  492. default:
  493. LOG_ERROR(TLS_SEV2, _T("Unexpected BitCount value"));
  494. bResult = FALSE;
  495. break;
  496. }
  497. m_nPixelDataSize =
  498. WidthBytes(pbih->bcWidth, pbih->bcBitCount) * pbih->bcHeight;
  499. return bResult;
  500. }
  501. //////////////////////////////////////////////////////////////////////////
  502. //
  503. // CCheckBmp::CheckBitmapInfoHeader
  504. //
  505. // Routine Description:
  506. // Checks BITMAPINFOHEADER
  507. //
  508. // Arguments:
  509. //
  510. // Return Value:
  511. //
  512. BOOL CCheckBmp::CheckBitmapInfoHeader()
  513. {
  514. PBITMAPINFOHEADER pbih = (PBITMAPINFOHEADER) m_pInfoHeader;
  515. BOOL bResult = TRUE;
  516. // biWidth
  517. // should be positive
  518. LOG_INFO(szDecVal, _T("Width"), pbih->biWidth);
  519. if (pbih->biWidth <= 0)
  520. {
  521. LOG_ERROR(TLS_SEV2, _T("Unexpected Width value"));
  522. bResult = FALSE;
  523. }
  524. // biHeight
  525. // should not be zero, if negative, should be BI_RGB or BI_BITFIELDS
  526. LOG_INFO(szDecVal, _T("Height"), pbih->biHeight);
  527. if (pbih->biHeight == 0)
  528. {
  529. LOG_ERROR(TLS_SEV2, _T("Unexpected Height value"));
  530. bResult = FALSE;
  531. }
  532. if (pbih->biHeight < 0)
  533. {
  534. switch (pbih->biCompression)
  535. {
  536. case BI_RGB:
  537. case BI_BITFIELDS:
  538. case BI_JPEG:
  539. case BI_PNG:
  540. break;
  541. default:
  542. LOG_ERROR(TLS_SEV2, _T("Unexpected Compression value for negative Height"));
  543. bResult = FALSE;
  544. break;
  545. }
  546. }
  547. // biPlanes
  548. // should be 1
  549. LOG_INFO(szDecVal, _T("Planes"), pbih->biPlanes);
  550. if (pbih->biPlanes != 1)
  551. {
  552. LOG_ERROR(TLS_SEV2, _T("Unexpected Planes value"));
  553. }
  554. // biBitCount
  555. // can be 0 (only for BI_JPEG or BI_PNG), 1, 4, 8, 16, 24 or 32
  556. LOG_INFO(szDecVal, _T("BitCount"), pbih->biBitCount);
  557. switch (pbih->biBitCount)
  558. {
  559. case 0:
  560. switch (pbih->biCompression)
  561. {
  562. case BI_JPEG:
  563. case BI_PNG:
  564. break;
  565. default:
  566. LOG_ERROR(TLS_SEV2, _T("Unexpected Compression value for zero BitCount"));
  567. bResult = FALSE;
  568. break;
  569. }
  570. break;
  571. case 1:
  572. case 4:
  573. case 8:
  574. m_nPaletteSize = (1 << pbih->biBitCount) * sizeof(RGBQUAD);
  575. break;
  576. case 16:
  577. case 24:
  578. case 32:
  579. m_nPaletteSize = 0;
  580. break;
  581. default:
  582. LOG_ERROR(TLS_SEV2, _T("Unexpected BitCount value"));
  583. bResult = FALSE;
  584. break;
  585. }
  586. // biCompression
  587. switch (pbih->biCompression)
  588. {
  589. case BI_RGB:
  590. LOG_INFO(szStrVal, _T("Compression"), _T("BI_RGB"));
  591. break;
  592. case BI_RLE8:
  593. LOG_INFO(szStrVal, _T("Compression"), _T("BI_RLE8"));
  594. if (pbih->biBitCount != 8)
  595. {
  596. LOG_ERROR(TLS_SEV2, _T("Unexpected BitCount value for BI_RLE8"));
  597. bResult = FALSE;
  598. }
  599. break;
  600. case BI_RLE4:
  601. LOG_INFO(szStrVal, _T("Compression"), _T("BI_RLE4"));
  602. if (pbih->biBitCount != 4)
  603. {
  604. LOG_ERROR(TLS_SEV2, _T("Unexpected BitCount value for BI_RLE4"));
  605. bResult = FALSE;
  606. }
  607. break;
  608. case BI_BITFIELDS:
  609. {
  610. LOG_INFO(szStrVal, _T("Compression"), _T("BI_BITFIELDS"));
  611. DWORD dwRedMask = ((PDWORD)(pbih + 1))[0];
  612. DWORD dwGreenMask = ((PDWORD)(pbih + 1))[1];
  613. DWORD dwBlueMask = ((PDWORD)(pbih + 1))[2];
  614. if (pbih->biSize == sizeof(BITMAPINFOHEADER))
  615. {
  616. m_nInfoHeaderSize += 3 * sizeof(DWORD);
  617. LOG_INFO(szHexVal, _T("RedMask"), dwRedMask);
  618. LOG_INFO(szHexVal, _T("GreenMask"), dwGreenMask);
  619. LOG_INFO(szHexVal, _T("BlueMask"), dwBlueMask);
  620. }
  621. switch (pbih->biBitCount)
  622. {
  623. case 16:
  624. if (
  625. (dwRedMask != 0x7C00 || dwGreenMask != 0x03E0 || dwBlueMask != 0x001F) &&
  626. (dwRedMask != 0xF800 || dwGreenMask != 0x07E0 || dwBlueMask != 0x001F)
  627. )
  628. {
  629. LOG_ERROR(TLS_WARN, _T("Unexpected color masks for Win9x BI_BITFIELDS"));
  630. }
  631. else
  632. {
  633. if ((dwRedMask | dwGreenMask | dwBlueMask) & 0xFFFF0000)
  634. {
  635. LOG_ERROR(TLS_SEV2, _T("Unexpected color masks for 16-bit BI_BITFIELDS"));
  636. bResult = FALSE;
  637. }
  638. if (!CheckColorMasks(dwRedMask, dwGreenMask, dwBlueMask))
  639. {
  640. LOG_ERROR(TLS_SEV2, _T("Unexpected color masks for BI_BITFIELDS"));
  641. bResult = FALSE;
  642. }
  643. }
  644. break;
  645. case 32:
  646. if (dwRedMask != 0x00FF0000 || dwGreenMask != 0x0000FF00 || dwBlueMask != 0x000000FF)
  647. {
  648. LOG_ERROR(TLS_WARN, _T("Unexpected color masks for Win9x BI_BITFIELDS"));
  649. }
  650. else
  651. {
  652. if (!CheckColorMasks(dwRedMask, dwGreenMask, dwBlueMask))
  653. {
  654. LOG_ERROR(TLS_SEV2, _T("Unexpected color masks for BI_BITFIELDS"));
  655. bResult = FALSE;
  656. }
  657. }
  658. break;
  659. default:
  660. LOG_ERROR(TLS_SEV2, _T("Unexpected BitCount for BI_BITFIELDS"));
  661. bResult = FALSE;
  662. break;
  663. }
  664. break;
  665. }
  666. case BI_JPEG:
  667. LOG_INFO(szStrVal, _T("Compression"), _T("BI_JPEG"));
  668. break;
  669. case BI_PNG:
  670. LOG_INFO(szStrVal, _T("Compression"), _T("BI_PNG"));
  671. break;
  672. default:
  673. LOG_INFO(szDecVal, _T("Compression"), pbih->biCompression);
  674. LOG_ERROR(TLS_SEV2, _T("Unexpected Compression value"));
  675. bResult = FALSE;
  676. break;
  677. }
  678. // biSizeImage
  679. // should not be negative, can be zero only for BI_RGB
  680. LOG_INFO(szDecVal, _T("SizeImage"), pbih->biSizeImage);
  681. if ((LONG) pbih->biSizeImage < 0)
  682. {
  683. LOG_ERROR(TLS_SEV2, _T("Unexpected SizeImage value"));
  684. bResult = FALSE;
  685. }
  686. m_nPixelDataSize =
  687. WidthBytes(Abs(pbih->biWidth), pbih->biBitCount) * Abs(pbih->biHeight);
  688. if (pbih->biSizeImage != 0)
  689. {
  690. if (pbih->biCompression == BI_RGB && m_nPixelDataSize != pbih->biSizeImage)
  691. {
  692. LOG_ERROR(TLS_SEV2, _T("Unexpected SizeImage value"));
  693. bResult = FALSE;
  694. }
  695. m_nPixelDataSize = pbih->biSizeImage;
  696. }
  697. else
  698. {
  699. if (pbih->biCompression != BI_RGB)
  700. {
  701. LOG_ERROR(TLS_SEV2, _T("Unexpected SizeImage value for non BI_RGB bitmap"));
  702. bResult = FALSE;
  703. }
  704. }
  705. // biClrUsed
  706. // should not be greater than the max number of bitdepth colors
  707. LOG_INFO(szDecVal, _T("ClrUsed"), pbih->biClrUsed);
  708. if (pbih->biClrUsed != 0)
  709. {
  710. if (pbih->biBitCount < 16 && pbih->biClrUsed * sizeof(RGBQUAD) > m_nPaletteSize)
  711. {
  712. LOG_ERROR(TLS_SEV2, _T("Unexpected ClrUsed value for the BitCount"));
  713. bResult = FALSE;
  714. }
  715. else
  716. {
  717. m_nPaletteSize = pbih->biClrUsed * sizeof(RGBQUAD);
  718. }
  719. }
  720. // biClrImportant
  721. // should be equal to or less than biClrUsed
  722. LOG_INFO(szDecVal, _T("ClrImportant"), pbih->biClrImportant);
  723. if (pbih->biClrUsed != 0 && pbih->biClrImportant > pbih->biClrUsed)
  724. {
  725. LOG_ERROR(TLS_SEV2, _T("Unexpected ClrImportant value"));
  726. bResult = FALSE;
  727. }
  728. return bResult;
  729. }
  730. //////////////////////////////////////////////////////////////////////////
  731. //
  732. // CCheckBmp::CheckBitmapV4Header
  733. //
  734. // Routine Description:
  735. // Checks BITMAPV4HEADER
  736. //
  737. // Arguments:
  738. //
  739. // Return Value:
  740. //
  741. BOOL CCheckBmp::CheckBitmapV4Header()
  742. {
  743. BOOL bResult = CheckBitmapInfoHeader();
  744. PBITMAPV4HEADER pbih = (PBITMAPV4HEADER) m_pInfoHeader;
  745. // bV4RedMask, bV4GreenMask, bV4BlueMask, bV4AlphaMask
  746. // already checked in the info header
  747. LOG_INFO(szHexVal, _T("RedMask"), pbih->bV4RedMask);
  748. LOG_INFO(szHexVal, _T("GreenMask"), pbih->bV4GreenMask);
  749. LOG_INFO(szHexVal, _T("BlueMask"), pbih->bV4BlueMask);
  750. LOG_INFO(szHexVal, _T("AlphaMask"), pbih->bV4AlphaMask);
  751. // bV4CSType
  752. // should be one of LCS_ types
  753. switch (pbih->bV4CSType)
  754. {
  755. case LCS_CALIBRATED_RGB:
  756. LOG_INFO(szStrVal, _T("CSType"), _T("LCS_CALIBRATED_RGB"));
  757. break;
  758. case LCS_sRGB:
  759. LOG_INFO(szStrVal, _T("CSType"), _T("LCS_sRGB"));
  760. break;
  761. case LCS_WINDOWS_COLOR_SPACE:
  762. LOG_INFO(szStrVal, _T("CSType"), _T("LCS_WINDOWS_COLOR_SPACE"));
  763. break;
  764. case PROFILE_LINKED:
  765. LOG_INFO(szStrVal, _T("CSType"), _T("PROFILE_LINKED"));
  766. break;
  767. case PROFILE_EMBEDDED:
  768. LOG_INFO(szStrVal, _T("CSType"), _T("PROFILE_EMBEDDED"));
  769. break;
  770. default:
  771. LOG_ERROR(TLS_SEV2, _T("Unexpected CSType value"));
  772. bResult = FALSE;
  773. break;
  774. }
  775. // bV4Endpoints, bV4GammaRed, bV4GammaGreen, bV4GammaBlue
  776. // should be present only for LCS_CALIBRATED_RGB
  777. LOG_INFO(szDblVal, _T("EndpointRedX"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzRed.ciexyzX));
  778. LOG_INFO(szDblVal, _T("EndpointRedY"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzRed.ciexyzY));
  779. LOG_INFO(szDblVal, _T("EndpointRedZ"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzRed.ciexyzZ));
  780. LOG_INFO(szDblVal, _T("EndpointGreenX"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzGreen.ciexyzX));
  781. LOG_INFO(szDblVal, _T("EndpointGreenY"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzGreen.ciexyzY));
  782. LOG_INFO(szDblVal, _T("EndpointGreenZ"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzGreen.ciexyzZ));
  783. LOG_INFO(szDblVal, _T("EndpointBlueX"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzBlue.ciexyzX));
  784. LOG_INFO(szDblVal, _T("EndpointBlueY"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzBlue.ciexyzY));
  785. LOG_INFO(szDblVal, _T("EndpointBlueZ"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzBlue.ciexyzZ));
  786. LOG_INFO(szDblVal, _T("GammaRed"), FXPT16DOT16_TO_FLPT(pbih->bV4GammaRed));
  787. LOG_INFO(szDblVal, _T("GammaGreen"), FXPT16DOT16_TO_FLPT(pbih->bV4GammaGreen));
  788. LOG_INFO(szDblVal, _T("GammaBlue"), FXPT16DOT16_TO_FLPT(pbih->bV4GammaBlue));
  789. if (pbih->bV4CSType != LCS_CALIBRATED_RGB)
  790. {
  791. // bugbug: how can I check a valid colorspace?
  792. if (
  793. pbih->bV4Endpoints.ciexyzRed.ciexyzX != 0 ||
  794. pbih->bV4Endpoints.ciexyzRed.ciexyzY != 0 ||
  795. pbih->bV4Endpoints.ciexyzRed.ciexyzZ != 0 ||
  796. pbih->bV4Endpoints.ciexyzGreen.ciexyzX != 0 ||
  797. pbih->bV4Endpoints.ciexyzGreen.ciexyzY != 0 ||
  798. pbih->bV4Endpoints.ciexyzGreen.ciexyzZ != 0 ||
  799. pbih->bV4Endpoints.ciexyzBlue.ciexyzX != 0 ||
  800. pbih->bV4Endpoints.ciexyzBlue.ciexyzY != 0 ||
  801. pbih->bV4Endpoints.ciexyzBlue.ciexyzZ != 0 ||
  802. pbih->bV4GammaRed != 0 ||
  803. pbih->bV4GammaGreen != 0 ||
  804. pbih->bV4GammaBlue != 0
  805. )
  806. {
  807. LOG_ERROR(TLS_SEV2, _T("Unexpected colorspace values for CSType"));
  808. bResult = FALSE;
  809. }
  810. }
  811. return bResult;
  812. }
  813. //////////////////////////////////////////////////////////////////////////
  814. //
  815. // CCheckBmp::CheckBitmapV5Header
  816. //
  817. // Routine Description:
  818. // Checks BITMAPV5HEADER
  819. //
  820. // Arguments:
  821. //
  822. // Return Value:
  823. //
  824. BOOL CCheckBmp::CheckBitmapV5Header()
  825. {
  826. BOOL bResult = CheckBitmapV4Header();
  827. PBITMAPV5HEADER pbih = (PBITMAPV5HEADER) m_pInfoHeader;
  828. // bV5Intent
  829. // should be one of the LCS_ values
  830. switch (pbih->bV5Intent)
  831. {
  832. case LCS_GM_BUSINESS:
  833. LOG_INFO(szStrVal, _T("Intent"), _T("LCS_GM_BUSINESS"));
  834. break;
  835. case LCS_GM_GRAPHICS:
  836. LOG_INFO(szStrVal, _T("Intent"), _T("LCS_GM_GRAPHICS"));
  837. break;
  838. case LCS_GM_IMAGES:
  839. LOG_INFO(szStrVal, _T("Intent"), _T("LCS_GM_IMAGES"));
  840. break;
  841. case LCS_GM_ABS_COLORIMETRIC:
  842. LOG_INFO(szStrVal, _T("Intent"), _T("LCS_GM_ABS_COLORIMETRIC"));
  843. break;
  844. default:
  845. LOG_ERROR(TLS_SEV2, _T("Unexpected Intent value"));
  846. bResult = FALSE;
  847. break;
  848. }
  849. // bV5ProfileData, bV5ProfileSize
  850. // check profile data
  851. LOG_INFO(szDecVal, _T("ProfileData"), pbih->bV5ProfileData);
  852. LOG_INFO(szDecVal, _T("ProfileSize"), pbih->bV5ProfileSize);
  853. switch (pbih->bV5CSType)
  854. {
  855. case LCS_CALIBRATED_RGB:
  856. case LCS_sRGB:
  857. case LCS_WINDOWS_COLOR_SPACE:
  858. if (pbih->bV5ProfileData != 0 || pbih->bV5ProfileSize != 0)
  859. {
  860. LOG_ERROR(TLS_SEV2, _T("Unexpected profile info for CSType"));
  861. bResult = FALSE;
  862. }
  863. break;
  864. case PROFILE_LINKED:
  865. {
  866. PCSTR pName = (PCSTR) ((PBYTE) pbih + pbih->bV5ProfileData);
  867. if (MultiByteToWideChar(1252, MB_ERR_INVALID_CHARS, pName, -1, 0, 0) == 0)
  868. {
  869. LOG_ERROR(TLS_SEV2, _T("Unexpected profile name for PROFILE_LINKED"));
  870. bResult = FALSE;
  871. }
  872. // continue,
  873. }
  874. case PROFILE_EMBEDDED:
  875. if (pbih->bV5ProfileData == 0 || pbih->bV5ProfileSize == 0)
  876. {
  877. LOG_ERROR(TLS_SEV2, _T("Unexpected profile info for CSType"));
  878. bResult = FALSE;
  879. }
  880. m_pProfile = (PBYTE) pbih + pbih->bV5ProfileData;
  881. m_nProfileSize = pbih->bV5ProfileSize;
  882. break;
  883. }
  884. // Reserved
  885. // should be zero
  886. LOG_INFO(szHexVal, _T("Reserved"), pbih->bV5Reserved);
  887. if (pbih->bV5Reserved != 0)
  888. {
  889. LOG_ERROR(TLS_SEV2, _T("Unexpected Reserved value"));
  890. bResult = FALSE;
  891. }
  892. return bResult;
  893. }
  894. //////////////////////////////////////////////////////////////////////////
  895. //
  896. // CheckBMPMain
  897. //
  898. // Routine Description:
  899. // _tmain() function in case someone runs this as a standalone program
  900. //
  901. // Arguments:
  902. //
  903. // Return Value:
  904. //
  905. void CheckBMPMain()
  906. {
  907. AllocCRTConsole();
  908. INT argc;
  909. CGlobalMem<PTSTR> argv(CommandLineToArgv(GetCommandLine(), &argc));
  910. CFullPathName FileName(argv[1]);
  911. for (
  912. CFindFile FindFile(FileName);
  913. FindFile.Found();
  914. FindFile.FindNextFile()
  915. )
  916. {
  917. FileName.SetFileName(FindFile.cFileName);
  918. LOG_INFO(FileName);
  919. CheckBmp((PCTSTR) FileName);
  920. }
  921. }